<commit_before>//! Definition of the triangle shape.

#[cfg(feature = "dim3")]
use arrayvec::ArrayVec;
#[cfg(feature = "dim3")]
use bounding_volume::ConicalApproximation;
use math::{Isometry, Point, Vector};
use na::Real;
use na::{self, Unit};
#[cfg(feature = "dim3")]
use query::{LocalShapeApproximation, NeighborhoodGeometry};
use shape::Segment;
use shape::SupportMap;
#[cfg(feature = "dim3")]
use shape::{ConvexPolygonalFeature, ConvexPolyhedron, FeatureId};
#[cfg(feature = "dim3")]
use std::f64;
use std::mem;
use utils::IsometryOps;

/// A triangle shape.
#[derive(PartialEq, Debug, Clone)]
pub struct Triangle<N: Real> {
    a: Point<N>,
    b: Point<N>,
    c: Point<N>,
}

/// Description of the location of a point on a triangle.
#[derive(Copy, Clone, Debug)]
pub enum TrianglePointLocation<N: Real> {
    /// The point lies on a vertex.
    OnVertex(usize),
    /// The point lies on an edge.
    ///
    /// The 0-st edge is the segment AB.
    /// The 1-st edge is the segment BC.
    /// The 2-nd edge is the segment AC.
    // XXX: it appears the conversion of edge indexing here does not match the
    // convension of edge indexing for the `fn edge` method (from the ConvexPolyhedron impl).
    OnEdge(usize, [N; 2]),
    /// The point lies on the triangle interior.
    ///
    /// The integer indicates on which side of the face the point is. 0 indicates the point
    /// is on the half-space toward the CW normal of the triangle. 1 indicates the point is on the other
    /// half-space. This is always set to 0 in 2D.
    OnFace(usize, [N; 3]),
    /// The point lies on the triangle interior (for "solid" point queries).
    OnSolid,
}

impl<N: Real> TrianglePointLocation<N> {
    /// The barycentric coordinates corresponding to this point location.
    ///
    /// Returns `None` if the location is `TrianglePointLocation::OnSolid`.
    pub fn barycentric_coordinates(&self) -> Option<[N; 3]> {
        let mut bcoords = [N::zero(); 3];

        match self {
            TrianglePointLocation::OnVertex(i) => bcoords[*i] = N::one(),
            TrianglePointLocation::OnEdge(i, uv) => {
                let idx = match i {
                    0 => (0, 1),
                    1 => (1, 2),
                    2 => (0, 2),
                    _ => unreachable!(),
                };

                bcoords[idx.0] = uv[0];
                bcoords[idx.1] = uv[1];
            }
            TrianglePointLocation::OnFace(_, uvw) => {
                bcoords[0] = uvw[0];
                bcoords[1] = uvw[1];
                bcoords[2] = uvw[2];
            }
            TrianglePointLocation::OnSolid => {
                return None;
            }
        }

        Some(bcoords)
    }

    /// Returns `true` if the point is located on the relative interior of the triangle.
    pub fn is_on_face(&self) -> bool {
        if let TrianglePointLocation::OnFace(..) = *self {
            true
        } else {
            false
        }
    }
}

impl<N: Real> Triangle<N> {
    /// Creates a triangle from three points.
    #[inline]
    pub fn new(a: Point<N>, b: Point<N>, c: Point<N>) -> Triangle<N> {
        Triangle { a, b, c }
    }

    /// Creates the reference to a triangle from the reference to an array of three points.
    pub fn from_array(arr: &[Point<N>; 3]) -> &Triangle<N> {
        unsafe { mem::transmute(arr) }
    }

    /// The fist point of this triangle.
    #[inline]
    pub fn a(&self) -> &Point<N> {
        &self.a
    }

    /// The second point of this triangle.
    #[inline]
    pub fn b(&self) -> &Point<N> {
        &self.b
    }

    /// The third point of this triangle.
    #[inline]
    pub fn c(&self) -> &Point<N> {
        &self.c
    }

    /// Reference to an array containing the three vertices of this triangle.
    #[inline]
    pub fn vertices(&self) -> &[Point<N>; 3] {
        unsafe { mem::transmute(self) }
    }

    /// The normal of this triangle assuming it is oriented ccw.
    ///
    /// The normal points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn normal(&self) -> Option<Unit<Vector<N>>> {
        Unit::try_new(self.scaled_normal(), N::default_epsilon())
    }

    /// The three edges of this triangle: [AB, BC, CA].
    #[inline]
    pub fn edges(&self) -> [Segment<N>; 3] {
        [
            Segment::new(self.a, self.b),
            Segment::new(self.b, self.c),
            Segment::new(self.c, self.a),
        ]
    }

    /// The three edges scaled directions of this triangle: [B - A, C - B, A - C].
    #[inline]
    pub fn edges_scaled_directions(&self) -> [Vector<N>; 3] {
        [self.b - self.a, self.c - self.b, self.a - self.c]
    }

    /// A vector normal of this triangle.
    ///
    /// The vector points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn scaled_normal(&self) -> Vector<N> {
        let ab = self.b - self.a;
        let ac = self.c - self.a;
        ab.cross(&ac)
    }

    /// Computes the extents of this triangle on the given direction.
    ///
    /// This computes the min and max values of the dot products between each
    /// vertex of this triangle and `dir`.
    #[inline]
    pub fn extents_on_dir(&self, dir: &Unit<Vector<N>>) -> (N, N) {
        let a = self.a.coords.dot(dir);
        let b = self.b.coords.dot(dir);
        let c = self.c.coords.dot(dir);

        if a > b {
            if b > c {
                (c, a)
            } else if a > c {
                (b, a)
            } else {
                (b, c)
            }
        } else {
            // b >= a
            if a > c {
                (c, b)
            } else if b > c {
                (a, b)
            } else {
                (a, c)
            }
        }
    }

    /// Checks that the given direction in world-space is on the tangent cone of the given `feature`.
    #[cfg(feature = "dim3")]
    #[inline]
    pub fn tangent_cone_contains_dir(
        &self,
        feature: FeatureId,
        m: &Isometry<N>,
        dir: &Unit<Vector<N>>,
    ) -> bool
    {
        let ls_dir = m.inverse_transform_vector(dir);

        if let Some(normal) = self.normal() {
            match feature {
                FeatureId::Vertex(_) => {
                    // FIXME: for now we assume since the triangle has no thickness,
                    // the case where `dir` is coplanar with the triangle never happens.
                    false
                }
                FeatureId::Edge(_) => {
                    // FIXME: for now we assume since the triangle has no thickness,
                    // the case where `dir` is coplanar with the triangle never happens.
                    false
                }
                FeatureId::Face(0) => ls_dir.dot(&normal) <= N::zero(),
                FeatureId::Face(1) => ls_dir.dot(&normal) >= N::zero(),
                _ => panic!("Invalid feature ID."),
            }
        } else {
            false
        }
    }
}

impl<N: Real> SupportMap<N> for Triangle<N> {
    #[inline]
    fn support_point(&self, m: &Isometry<N>, dir: &Vector<N>) -> Point<N> {
        let local_dir = m.inverse_transform_vector(dir);

        let d1 = na::dot(&self.a().coords, &local_dir);
        let d2 = na::dot(&self.b().coords, &local_dir);
        let d3 = na::dot(&self.c().coords, &local_dir);

        let res = if d1 > d2 {
            if d1 > d3 {
                self.a()
            } else {
                self.c()
            }
        } else {
            if d2 > d3 {
                self.b()
            } else {
                self.c()
            }
        };

        m * res
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> ConvexPolyhedron<N> for Triangle<N> {
    fn vertex(&self, id: FeatureId) -> Point<N> {
        match id.unwrap_vertex() {
            0 => self.a,
            1 => self.b,
            2 => self.c,
            _ => panic!("Triangle vertex index out of bounds."),
        }
    }
    fn edge(&self, id: FeatureId) -> (Point<N>, Point<N>, FeatureId, FeatureId) {
        match id.unwrap_edge() {
            0 => (self.a, self.b, FeatureId::Vertex(0), FeatureId::Vertex(1)),
            1 => (self.b, self.c, FeatureId::Vertex(1), FeatureId::Vertex(2)),
            2 => (self.c, self.a, FeatureId::Vertex(2), FeatureId::Vertex(0)),
            _ => panic!("Triangle edge index out of bounds."),
        }
    }

    fn face(&self, id: FeatureId, face: &mut ConvexPolygonalFeature<N>) {
        face.clear();

        if let Some(normal) = self.normal() {
            face.set_feature_id(id);

            match id.unwrap_face() {
                0 => {
                    face.push(self.a, FeatureId::Vertex(0));
                    face.push(self.b, FeatureId::Vertex(1));
                    face.push(self.c, FeatureId::Vertex(2));
                    face.push_edge_feature_id(FeatureId::Edge(0));
                    face.push_edge_feature_id(FeatureId::Edge(1));
                    face.push_edge_feature_id(FeatureId::Edge(2));
                    face.set_normal(normal);
                }
                1 => {
                    face.push(self.a, FeatureId::Vertex(0));
                    face.push(self.c, FeatureId::Vertex(2));
                    face.push(self.b, FeatureId::Vertex(1));
                    face.push_edge_feature_id(FeatureId::Edge(2));
                    face.push_edge_feature_id(FeatureId::Edge(1));
                    face.push_edge_feature_id(FeatureId::Edge(0));
                    face.set_normal(-normal);
                }
                _ => unreachable!(),
            }

            face.recompute_edge_normals();
        } else {
            face.push(self.a, FeatureId::Vertex(0));
            face.set_feature_id(FeatureId::Vertex(0));
        }
    }

    fn normal_cone(&self, feature: FeatureId) -> ConicalApproximation<N> {
        if let Some(normal) = self.normal() {
            match feature {
                FeatureId::Vertex(id2) => {
                    let vtx = self.vertices();
                    let mut generators = ArrayVec::new();
                    let id1 = if id2 == 0 { 2 } else { id2 - 1 };
                    let id3 = (id2 + 1) % 3;

                    if let Some(side1) = Unit::try_new(vtx[id2] - vtx[id1], N::default_epsilon()) {
                        generators.push(side1);
                    }
                    generators.push(-normal);
                    if let Some(side2) = Unit::try_new(vtx[id3] - vtx[id2], N::default_epsilon()) {
                        generators.push(side2);
                    }
                    generators.push(normal);

                    // FIXME: is it meaningful not to push the sides if the triangle is degenerate?

                    ConicalApproximation::Span(generators)
                }
                FeatureId::Edge(id1) => {
                    // FIXME: We should be able to do much better here.
                    let id2 = (id1 + 1) % 3;
                    let vtx = self.vertices();
                    let mut generators = ArrayVec::new();

                    if let Some(side) = Unit::try_new(vtx[id2] - vtx[id1], N::default_epsilon()) {
                        generators.push(side);
                        generators.push(-normal);
                        generators.push(side);
                        generators.push(normal);
                    } else {
                        // FIXME: is this meaningful?
                        generators.push(-normal);
                        generators.push(normal);
                    }

                    ConicalApproximation::Span(generators)
                }
                FeatureId::Face(0) => ConicalApproximation::HalfLine(normal),
                FeatureId::Face(1) => ConicalApproximation::HalfLine(-normal),
                _ => panic!("Invalid feature ID."),
            }
        } else {
            ConicalApproximation::Full
        }
    }

    fn support_face_toward(
        &self,
        m: &Isometry<N>,
        dir: &Unit<Vector<N>>,
        face: &mut ConvexPolygonalFeature<N>,
    )
    {
        let normal = self.scaled_normal();

        if na::dot(&normal, &*dir) >= na::zero() {
            ConvexPolyhedron::<N>::face(self, FeatureId::Face(0), face);
        } else {
            ConvexPolyhedron::<N>::face(self, FeatureId::Face(1), face);
        }
        face.transform_by(m)
    }

    fn support_feature_toward(
        &self,
        transform: &Isometry<N>,
        dir: &Unit<Vector<N>>,
        _angle: N,
        out: &mut ConvexPolygonalFeature<N>,
    )
    {
        out.clear();
        // FIXME: actualy find the support feature.
        self.support_face_toward(transform, dir, out)
    }

    fn support_feature_id_toward(&self, local_dir: &Unit<Vector<N>>) -> FeatureId {
        if let Some(normal) = self.normal() {
            let eps: N = na::convert(f64::consts::PI / 180.0);
            let ceps = eps.cos();

            let normal_dot = local_dir.dot(&*normal);
            if normal_dot >= ceps {
                FeatureId::Face(0)
            } else if normal_dot <= -ceps {
                FeatureId::Face(1)
            } else {
                let dot1 = local_dir.dot(&self.a.coords);
                let dot2 = local_dir.dot(&self.b.coords);
                let dot3 = local_dir.dot(&self.c.coords);

                if dot1 > dot2 {
                    if dot1 > dot3 {
                        FeatureId::Vertex(0)
                    } else {
                        FeatureId::Vertex(2)
                    }
                } else if dot2 > dot3 {
                    FeatureId::Vertex(1)
                } else {
                    FeatureId::Vertex(2)
                }
            }
        } else {
            FeatureId::Vertex(0)
        }
    }
}
<commit_msg>Fix triangle extremal feature computation.<commit_after>//! Definition of the triangle shape.

#[cfg(feature = "dim3")]
use arrayvec::ArrayVec;
#[cfg(feature = "dim3")]
use bounding_volume::ConicalApproximation;
use math::{Isometry, Point, Vector};
use na::Real;
use na::{self, Unit};
#[cfg(feature = "dim3")]
use query::{LocalShapeApproximation, NeighborhoodGeometry};
use shape::Segment;
use shape::SupportMap;
#[cfg(feature = "dim3")]
use shape::{ConvexPolygonalFeature, ConvexPolyhedron, FeatureId};
#[cfg(feature = "dim3")]
use std::f64;
use std::mem;
use utils::IsometryOps;

/// A triangle shape.
#[derive(PartialEq, Debug, Clone)]
pub struct Triangle<N: Real> {
    a: Point<N>,
    b: Point<N>,
    c: Point<N>,
}

/// Description of the location of a point on a triangle.
#[derive(Copy, Clone, Debug)]
pub enum TrianglePointLocation<N: Real> {
    /// The point lies on a vertex.
    OnVertex(usize),
    /// The point lies on an edge.
    ///
    /// The 0-st edge is the segment AB.
    /// The 1-st edge is the segment BC.
    /// The 2-nd edge is the segment AC.
    // XXX: it appears the conversion of edge indexing here does not match the
    // convension of edge indexing for the `fn edge` method (from the ConvexPolyhedron impl).
    OnEdge(usize, [N; 2]),
    /// The point lies on the triangle interior.
    ///
    /// The integer indicates on which side of the face the point is. 0 indicates the point
    /// is on the half-space toward the CW normal of the triangle. 1 indicates the point is on the other
    /// half-space. This is always set to 0 in 2D.
    OnFace(usize, [N; 3]),
    /// The point lies on the triangle interior (for "solid" point queries).
    OnSolid,
}

impl<N: Real> TrianglePointLocation<N> {
    /// The barycentric coordinates corresponding to this point location.
    ///
    /// Returns `None` if the location is `TrianglePointLocation::OnSolid`.
    pub fn barycentric_coordinates(&self) -> Option<[N; 3]> {
        let mut bcoords = [N::zero(); 3];

        match self {
            TrianglePointLocation::OnVertex(i) => bcoords[*i] = N::one(),
            TrianglePointLocation::OnEdge(i, uv) => {
                let idx = match i {
                    0 => (0, 1),
                    1 => (1, 2),
                    2 => (0, 2),
                    _ => unreachable!(),
                };

                bcoords[idx.0] = uv[0];
                bcoords[idx.1] = uv[1];
            }
            TrianglePointLocation::OnFace(_, uvw) => {
                bcoords[0] = uvw[0];
                bcoords[1] = uvw[1];
                bcoords[2] = uvw[2];
            }
            TrianglePointLocation::OnSolid => {
                return None;
            }
        }

        Some(bcoords)
    }

    /// Returns `true` if the point is located on the relative interior of the triangle.
    pub fn is_on_face(&self) -> bool {
        if let TrianglePointLocation::OnFace(..) = *self {
            true
        } else {
            false
        }
    }
}

impl<N: Real> Triangle<N> {
    /// Creates a triangle from three points.
    #[inline]
    pub fn new(a: Point<N>, b: Point<N>, c: Point<N>) -> Triangle<N> {
        Triangle { a, b, c }
    }

    /// Creates the reference to a triangle from the reference to an array of three points.
    pub fn from_array(arr: &[Point<N>; 3]) -> &Triangle<N> {
        unsafe { mem::transmute(arr) }
    }

    /// The fist point of this triangle.
    #[inline]
    pub fn a(&self) -> &Point<N> {
        &self.a
    }

    /// The second point of this triangle.
    #[inline]
    pub fn b(&self) -> &Point<N> {
        &self.b
    }

    /// The third point of this triangle.
    #[inline]
    pub fn c(&self) -> &Point<N> {
        &self.c
    }

    /// Reference to an array containing the three vertices of this triangle.
    #[inline]
    pub fn vertices(&self) -> &[Point<N>; 3] {
        unsafe { mem::transmute(self) }
    }

    /// The normal of this triangle assuming it is oriented ccw.
    ///
    /// The normal points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn normal(&self) -> Option<Unit<Vector<N>>> {
        Unit::try_new(self.scaled_normal(), N::default_epsilon())
    }

    /// The three edges of this triangle: [AB, BC, CA].
    #[inline]
    pub fn edges(&self) -> [Segment<N>; 3] {
        [
            Segment::new(self.a, self.b),
            Segment::new(self.b, self.c),
            Segment::new(self.c, self.a),
        ]
    }

    /// Returns a new triangle with vertices transformed by `m`.
    #[inline]
    pub fn transformed(&self, m: &Isometry<N>) -> Self {
        Triangle::new(m * self.a, m * self.b, m * self.c)
    }
    /// The three edges scaled directions of this triangle: [B - A, C - B, A - C].
    #[inline]
    pub fn edges_scaled_directions(&self) -> [Vector<N>; 3] {
        [self.b - self.a, self.c - self.b, self.a - self.c]
    }

    /// A vector normal of this triangle.
    ///
    /// The vector points such that it is collinear to `AB × AC` (where `×` denotes the cross
    /// product).
    #[inline]
    pub fn scaled_normal(&self) -> Vector<N> {
        let ab = self.b - self.a;
        let ac = self.c - self.a;
        ab.cross(&ac)
    }

    /// Computes the extents of this triangle on the given direction.
    ///
    /// This computes the min and max values of the dot products between each
    /// vertex of this triangle and `dir`.
    #[inline]
    pub fn extents_on_dir(&self, dir: &Unit<Vector<N>>) -> (N, N) {
        let a = self.a.coords.dot(dir);
        let b = self.b.coords.dot(dir);
        let c = self.c.coords.dot(dir);

        if a > b {
            if b > c {
                (c, a)
            } else if a > c {
                (b, a)
            } else {
                (b, c)
            }
        } else {
            // b >= a
            if a > c {
                (c, b)
            } else if b > c {
                (a, b)
            } else {
                (a, c)
            }
        }
    }

    /// Checks that the given direction in world-space is on the tangent cone of the given `feature`.
    #[cfg(feature = "dim3")]
    #[inline]
    pub fn tangent_cone_contains_dir(
        &self,
        feature: FeatureId,
        m: &Isometry<N>,
        dir: &Unit<Vector<N>>,
    ) -> bool
    {
        let ls_dir = m.inverse_transform_vector(dir);

        if let Some(normal) = self.normal() {
            match feature {
                FeatureId::Vertex(_) => {
                    // FIXME: for now we assume since the triangle has no thickness,
                    // the case where `dir` is coplanar with the triangle never happens.
                    false
                }
                FeatureId::Edge(_) => {
                    // FIXME: for now we assume since the triangle has no thickness,
                    // the case where `dir` is coplanar with the triangle never happens.
                    false
                }
                FeatureId::Face(0) => ls_dir.dot(&normal) <= N::zero(),
                FeatureId::Face(1) => ls_dir.dot(&normal) >= N::zero(),
                _ => panic!("Invalid feature ID."),
            }
        } else {
            false
        }
    }

    #[cfg(feature = "dim3")]
    fn support_feature_id_toward(&self, local_dir: &Unit<Vector<N>>, eps: N) -> FeatureId {
        if let Some(normal) = self.normal() {
            let (seps, ceps) = eps.sin_cos();

            let normal_dot = local_dir.dot(&*normal);
            if normal_dot >= ceps {
                FeatureId::Face(0)
            } else if normal_dot <= -ceps {
                FeatureId::Face(1)
            } else {
                let edges = self.edges();
                let mut dots = [N::zero(); 3];

                let dir1 = edges[0].direction();
                if let Some(dir1) = dir1 {
                    dots[0] = dir1.dot(local_dir);

                    if dots[0].abs() < seps {
                        return FeatureId::Edge(0);
                    }
                }

                let dir2 = edges[1].direction();
                if let Some(dir2) = dir2 {
                    dots[1] = dir2.dot(local_dir);

                    if dots[1].abs() < seps {
                        return FeatureId::Edge(1);
                    }
                }

                let dir3 = edges[2].direction();
                if let Some(dir3) = dir3 {
                    dots[2] = dir3.dot(local_dir);

                    if dots[2].abs() < seps {
                        return FeatureId::Edge(2);
                    }
                }

                if dots[0] > N::zero() && dots[1] < N::zero() {
                    FeatureId::Vertex(1)
                } else if dots[1] > N::zero() && dots[2] < N::zero() {
                    FeatureId::Vertex(2)
                } else {
                    FeatureId::Vertex(0)
                }
            }
        } else {
            FeatureId::Vertex(0)
        }
    }
}

impl<N: Real> SupportMap<N> for Triangle<N> {
    #[inline]
    fn support_point(&self, m: &Isometry<N>, dir: &Vector<N>) -> Point<N> {
        let local_dir = m.inverse_transform_vector(dir);

        let d1 = na::dot(&self.a().coords, &local_dir);
        let d2 = na::dot(&self.b().coords, &local_dir);
        let d3 = na::dot(&self.c().coords, &local_dir);

        let res = if d1 > d2 {
            if d1 > d3 {
                self.a()
            } else {
                self.c()
            }
        } else {
            if d2 > d3 {
                self.b()
            } else {
                self.c()
            }
        };

        m * res
    }
}

#[cfg(feature = "dim3")]
impl<N: Real> ConvexPolyhedron<N> for Triangle<N> {
    fn vertex(&self, id: FeatureId) -> Point<N> {
        match id.unwrap_vertex() {
            0 => self.a,
            1 => self.b,
            2 => self.c,
            _ => panic!("Triangle vertex index out of bounds."),
        }
    }
    fn edge(&self, id: FeatureId) -> (Point<N>, Point<N>, FeatureId, FeatureId) {
        match id.unwrap_edge() {
            0 => (self.a, self.b, FeatureId::Vertex(0), FeatureId::Vertex(1)),
            1 => (self.b, self.c, FeatureId::Vertex(1), FeatureId::Vertex(2)),
            2 => (self.c, self.a, FeatureId::Vertex(2), FeatureId::Vertex(0)),
            _ => panic!("Triangle edge index out of bounds."),
        }
    }

    fn face(&self, id: FeatureId, face: &mut ConvexPolygonalFeature<N>) {
        face.clear();

        if let Some(normal) = self.normal() {
            face.set_feature_id(id);

            match id.unwrap_face() {
                0 => {
                    face.push(self.a, FeatureId::Vertex(0));
                    face.push(self.b, FeatureId::Vertex(1));
                    face.push(self.c, FeatureId::Vertex(2));
                    face.push_edge_feature_id(FeatureId::Edge(0));
                    face.push_edge_feature_id(FeatureId::Edge(1));
                    face.push_edge_feature_id(FeatureId::Edge(2));
                    face.set_normal(normal);
                }
                1 => {
                    face.push(self.a, FeatureId::Vertex(0));
                    face.push(self.c, FeatureId::Vertex(2));
                    face.push(self.b, FeatureId::Vertex(1));
                    face.push_edge_feature_id(FeatureId::Edge(2));
                    face.push_edge_feature_id(FeatureId::Edge(1));
                    face.push_edge_feature_id(FeatureId::Edge(0));
                    face.set_normal(-normal);
                }
                _ => unreachable!(),
            }

            face.recompute_edge_normals();
        } else {
            face.push(self.a, FeatureId::Vertex(0));
            face.set_feature_id(FeatureId::Vertex(0));
        }
    }

    fn normal_cone(&self, feature: FeatureId) -> ConicalApproximation<N> {
        if let Some(normal) = self.normal() {
            match feature {
                FeatureId::Vertex(id2) => {
                    let vtx = self.vertices();
                    let mut generators = ArrayVec::new();
                    let id1 = if id2 == 0 { 2 } else { id2 - 1 };
                    let id3 = (id2 + 1) % 3;

                    if let Some(side1) = Unit::try_new(vtx[id2] - vtx[id1], N::default_epsilon()) {
                        generators.push(side1);
                    }
                    generators.push(-normal);
                    if let Some(side2) = Unit::try_new(vtx[id3] - vtx[id2], N::default_epsilon()) {
                        generators.push(side2);
                    }
                    generators.push(normal);

                    // FIXME: is it meaningful not to push the sides if the triangle is degenerate?

                    ConicalApproximation::Span(generators)
                }
                FeatureId::Edge(id1) => {
                    // FIXME: We should be able to do much better here.
                    let id2 = (id1 + 1) % 3;
                    let vtx = self.vertices();
                    let mut generators = ArrayVec::new();

                    if let Some(side) = Unit::try_new(vtx[id2] - vtx[id1], N::default_epsilon()) {
                        generators.push(side);
                        generators.push(-normal);
                        generators.push(side);
                        generators.push(normal);
                    } else {
                        // FIXME: is this meaningful?
                        generators.push(-normal);
                        generators.push(normal);
                    }

                    ConicalApproximation::Span(generators)
                }
                FeatureId::Face(0) => ConicalApproximation::HalfLine(normal),
                FeatureId::Face(1) => ConicalApproximation::HalfLine(-normal),
                _ => panic!("Invalid feature ID."),
            }
        } else {
            ConicalApproximation::Full
        }
    }

    fn support_face_toward(
        &self,
        m: &Isometry<N>,
        dir: &Unit<Vector<N>>,
        face: &mut ConvexPolygonalFeature<N>,
    )
    {
        let normal = self.scaled_normal();

        if na::dot(&normal, &*dir) >= na::zero() {
            ConvexPolyhedron::<N>::face(self, FeatureId::Face(0), face);
        } else {
            ConvexPolyhedron::<N>::face(self, FeatureId::Face(1), face);
        }
        face.transform_by(m)
    }

    fn support_feature_toward(
        &self,
        transform: &Isometry<N>,
        dir: &Unit<Vector<N>>,
        eps: N,
        out: &mut ConvexPolygonalFeature<N>,
    )
    {
        out.clear();
        let tri = self.transformed(transform);
        let feature = tri.support_feature_id_toward(dir, eps);

        match feature {
            FeatureId::Vertex(_) => {
                let v = tri.vertex(feature);
                out.push(v, feature);
                out.set_feature_id(feature);
            }
            FeatureId::Edge(_) => {
                let (a, b, fa, fb) = tri.edge(feature);
                out.push(a, fa);
                out.push(b, fb);
                out.push_edge_feature_id(feature);
                out.set_feature_id(feature);
            }
            FeatureId::Face(_) => {
                tri.face(feature, out)
            }
            _ => unreachable!()
        }

    }

    fn support_feature_id_toward(&self, local_dir: &Unit<Vector<N>>) -> FeatureId {
        self.support_feature_id_toward(local_dir,  na::convert(f64::consts::PI / 180.0))
    }
}
<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Types and traits for representing simulation algorithms
pub mod propagator;
pub use self::propagator::Propagator;

mod simulations;
pub use self::simulations::Simulation;

pub mod md;
pub use self::md::*;

pub mod mc;
pub use self::mc::*;

pub mod minimization;
pub use self::minimization::*;

pub mod outputs;
pub use self::outputs::Output;
pub use self::outputs::{TrajectoryOutput, CellOutput, EnergyOutput};
<commit_msg>Missing export<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Types and traits for representing simulation algorithms
pub mod propagator;
pub use self::propagator::Propagator;

mod simulations;
pub use self::simulations::Simulation;

pub mod md;
pub use self::md::*;

pub mod mc;
pub use self::mc::*;

pub mod minimization;
pub use self::minimization::*;

pub mod outputs;
pub use self::outputs::Output;
pub use self::outputs::{TrajectoryOutput, CellOutput, EnergyOutput, PropertiesOutput};
<|endoftext|>


<commit_before>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    find, get_features_from_registry, get_manifest_from_url, registry_url, workspace_members,
    Dependency, LocalManifest,
};
use cargo_edit::{get_latest_dependency, CrateSpec};
use cargo_metadata::Package;
use clap::Parser;
use std::path::PathBuf;

use crate::errors::*;

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub enum Command {
    /// Add dependencies to a Cargo.toml manifest file.
    #[clap(name = "add")]
    #[clap(after_help = "\
Examples:
  $ cargo add regex
  $ cargo add regex@0.1.41 --build
  $ cargo add trycmd --dev
  $ cargo add ./crate/parser/
")]
    Add(Args),
}

#[derive(Debug, Parser)]
#[clap(about, version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct Args {
    /// Reference to a package to add as a dependency
    ///
    /// You can reference a packages by:{n}
    /// - `<name>`, like `cargo add serde` (latest version will be used){n}
    /// - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`{n}
    /// - `<path>`, like `cargo add ./crates/parser/`
    #[clap(value_name = "DEP_ID", required = true)]
    pub crates: Vec<String>,

    /// Disable the default features
    #[clap(long)]
    no_default_features: bool,
    /// Re-enable the default features
    #[clap(long, overrides_with = "no-default-features")]
    default_features: bool,

    /// Space-separated list of features to add
    #[clap(long)]
    pub features: Option<Vec<String>>,

    /// Mark the dependency as optional
    ///
    /// The package name will be exposed as feature of your crate.
    #[clap(long, conflicts_with = "dev")]
    pub optional: bool,

    /// Mark the dependency as required
    ///
    /// The package will be removed from your features.
    #[clap(long, conflicts_with = "dev", overrides_with = "optional")]
    pub no_optional: bool,

    /// Rename the dependency
    ///
    /// Example uses:{n}
    /// - Depending on multiple versions of a crate{n}
    /// - Depend on crates with the same name from different registries
    #[clap(long, short)]
    pub rename: Option<String>,

    /// Package registry for this dependency
    #[clap(long, conflicts_with = "git")]
    pub registry: Option<String>,

    /// Add as development dependency
    ///
    /// Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
    ///
    /// These dependencies are not propagated to other packages which depend on this package.
    #[clap(short = 'D', long, help_heading = "SECTION", group = "section")]
    pub dev: bool,

    /// Add as build dependency
    ///
    /// Build-dependencies are the only dependencies available for use by build scripts (`build.rs`
    /// files).
    #[clap(short = 'B', long, help_heading = "SECTION", group = "section")]
    pub build: bool,

    /// Add as dependency to the given target platform.
    #[clap(
        long,
        forbid_empty_values = true,
        help_heading = "SECTION",
        group = "section"
    )]
    pub target: Option<String>,

    /// Path to `Cargo.toml`
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to modify
    #[clap(short = 'p', long = "package", value_name = "PKGID")]
    pub pkgid: Option<String>,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Do not print any output in case of success.
    #[clap(long)]
    pub quiet: bool,

    /// Unstable (nightly-only) flags
    #[clap(
        short = 'Z',
        value_name = "FLAG",
        help_heading = "UNSTABLE",
        global = true,
        arg_enum
    )]
    pub unstable_features: Vec<UnstableOptions>,

    /// Git repository location
    ///
    /// Without any other information, cargo will use latest commit on the main branch.
    #[clap(long, value_name = "URI", help_heading = "UNSTABLE")]
    pub git: Option<String>,

    /// Git branch to download the crate from.
    #[clap(
        long,
        value_name = "BRANCH",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub branch: Option<String>,

    /// Git tag to download the crate from.
    #[clap(
        long,
        value_name = "TAG",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub tag: Option<String>,

    /// Git reference to download the crate from
    ///
    /// This is the catch all, handling hashes to named references in remote repositories.
    #[clap(
        long,
        value_name = "REV",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub rev: Option<String>,
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    pub fn default_features(&self) -> Option<bool> {
        resolve_bool_arg(self.default_features, self.no_default_features)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self, manifest: &LocalManifest) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1 && self.git.is_some() {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_spec| {
                self.parse_single_dependency(manifest, crate_spec, &workspace_members)
            })
            .collect()
    }

    fn parse_single_dependency(
        &self,
        manifest: &LocalManifest,
        crate_spec: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_spec = CrateSpec::resolve(crate_spec)?;
        let manifest_path = find(&self.manifest_path)?;
        let registry_url = registry_url(&manifest_path, self.registry.as_deref())?;

        let mut dependency = match &crate_spec {
            CrateSpec::PkgId {
                name: _,
                version_req: Some(_),
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);
                // crate specifier includes a version (e.g. `docopt@0.8`)
                if let Some(ref url) = self.git {
                    let url = url.clone();
                    let version = dependency.version().unwrap().to_string();
                    return Err(ErrorKind::GitUrlWithVersion(url, version).into());
                }

                let features = get_features_from_registry(
                    &dependency.name,
                    dependency
                        .version()
                        .expect("version populated by `parse_as_version`"),
                    &registry_url,
                )?;
                dependency = dependency.set_available_features(features);

                dependency
            }
            CrateSpec::PkgId {
                name,
                version_req: None,
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                if let Some(repo) = &self.git {
                    assert!(self.registry.is_none());
                    let features = get_manifest_from_url(repo)?
                        .map(|m| m.features())
                        .transpose()?
                        .unwrap_or_else(Vec::new);

                    dependency = dependency
                        .set_git(
                            repo,
                            self.branch.clone(),
                            self.tag.clone(),
                            self.rev.clone(),
                        )
                        .set_available_features(features);
                } else if let Some(version) =
                    manifest.get_dep_version(&self.get_section(), dependency.toml_key())
                {
                    let features =
                        get_features_from_registry(&dependency.name, &version, &registry_url)?;
                    dependency = dependency
                        .set_version(&version)
                        .set_available_features(features);
                } else if let Some(package) = workspace_members.iter().find(|p| p.name == *name) {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    dependency = dependency.set_path(
                        package
                            .manifest_path
                            .parent()
                            .expect("at least parent dir")
                            .as_std_path()
                            .to_owned(),
                    );
                    // dev-dependencies do not need the version populated
                    if !self.dev {
                        let op = "";
                        let v = format!("{op}{version}", op = op, version = package.version);
                        dependency = dependency.set_version(&v);
                    }
                } else {
                    let latest =
                        get_latest_dependency(name, false, &manifest_path, Some(&registry_url))?;
                    let op = "";
                    let v = format!(
                        "{op}{version}",
                        op = op,
                        // If version is unavailable `get_latest_dependency` must have
                        // returned `Err(FetchVersionError::GetVersion)`
                        version = latest.version().unwrap_or_else(|| unreachable!())
                    );
                    dependency = dependency
                        .set_version(&v)
                        .set_available_features(latest.available_features);
                }

                dependency
            }
            CrateSpec::Path(_) => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                // dev-dependencies do not need the version populated
                if !self.dev {
                    let dep_path = dependency.path().map(ToOwned::to_owned);
                    if let Some(dep_path) = dep_path {
                        if let Some(package) = workspace_members.iter().find(|p| {
                            p.manifest_path.parent().map(|p| p.as_std_path())
                                == Some(dep_path.as_path())
                        }) {
                            let op = "";
                            let v = format!("{op}{version}", op = op, version = package.version);

                            dependency = dependency.set_version(&v);
                        }
                    }
                }
                dependency
            }
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }

        Ok(dependency)
    }

    fn populate_dependency(&self, mut dependency: Dependency) -> Dependency {
        let requested_features: Option<Vec<_>> = self.features.as_ref().map(|v| {
            v.iter()
                .flat_map(|s| s.split(' '))
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(|f| f.to_owned())
                .collect()
        });

        dependency = dependency
            .set_optional(self.optional())
            .set_default_features(self.default_features())
            .set_features(requested_features);

        if let Some(ref rename) = self.rename {
            dependency = dependency.set_rename(rename);
        }

        dependency
    }
}

impl Args {
    pub fn optional(&self) -> Option<bool> {
        resolve_bool_arg(self.optional, self.no_optional)
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            git: None,
            branch: None,
            tag: None,
            rev: None,
            target: None,
            optional: false,
            no_optional: false,
            manifest_path: None,
            pkgid: None,
            features: None,
            no_default_features: false,
            default_features: false,
            quiet: false,
            offline: true,
            registry: None,
            unstable_features: vec![],
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
pub enum UnstableOptions {
    Git,
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
    match (yes, no) {
        (true, false) => Some(true),
        (false, true) => Some(false),
        (false, false) => None,
        (_, _) => unreachable!("clap should make this impossible"),
    }
}

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

    #[test]
    fn verify_app() {
        use clap::IntoApp;
        Command::into_app().debug_assert()
    }
}
<commit_msg>refactor(add): Remove redundant lookup<commit_after>//! Handle `cargo add` arguments

#![allow(clippy::bool_assert_comparison)]

use cargo_edit::{
    get_features_from_registry, get_manifest_from_url, registry_url, workspace_members, Dependency,
    LocalManifest,
};
use cargo_edit::{get_latest_dependency, CrateSpec};
use cargo_metadata::Package;
use clap::Parser;
use std::path::PathBuf;

use crate::errors::*;

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub enum Command {
    /// Add dependencies to a Cargo.toml manifest file.
    #[clap(name = "add")]
    #[clap(after_help = "\
Examples:
  $ cargo add regex
  $ cargo add regex@0.1.41 --build
  $ cargo add trycmd --dev
  $ cargo add ./crate/parser/
")]
    Add(Args),
}

#[derive(Debug, Parser)]
#[clap(about, version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct Args {
    /// Reference to a package to add as a dependency
    ///
    /// You can reference a packages by:{n}
    /// - `<name>`, like `cargo add serde` (latest version will be used){n}
    /// - `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`{n}
    /// - `<path>`, like `cargo add ./crates/parser/`
    #[clap(value_name = "DEP_ID", required = true)]
    pub crates: Vec<String>,

    /// Disable the default features
    #[clap(long)]
    no_default_features: bool,
    /// Re-enable the default features
    #[clap(long, overrides_with = "no-default-features")]
    default_features: bool,

    /// Space-separated list of features to add
    #[clap(long)]
    pub features: Option<Vec<String>>,

    /// Mark the dependency as optional
    ///
    /// The package name will be exposed as feature of your crate.
    #[clap(long, conflicts_with = "dev")]
    pub optional: bool,

    /// Mark the dependency as required
    ///
    /// The package will be removed from your features.
    #[clap(long, conflicts_with = "dev", overrides_with = "optional")]
    pub no_optional: bool,

    /// Rename the dependency
    ///
    /// Example uses:{n}
    /// - Depending on multiple versions of a crate{n}
    /// - Depend on crates with the same name from different registries
    #[clap(long, short)]
    pub rename: Option<String>,

    /// Package registry for this dependency
    #[clap(long, conflicts_with = "git")]
    pub registry: Option<String>,

    /// Add as development dependency
    ///
    /// Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
    ///
    /// These dependencies are not propagated to other packages which depend on this package.
    #[clap(short = 'D', long, help_heading = "SECTION", group = "section")]
    pub dev: bool,

    /// Add as build dependency
    ///
    /// Build-dependencies are the only dependencies available for use by build scripts (`build.rs`
    /// files).
    #[clap(short = 'B', long, help_heading = "SECTION", group = "section")]
    pub build: bool,

    /// Add as dependency to the given target platform.
    #[clap(
        long,
        forbid_empty_values = true,
        help_heading = "SECTION",
        group = "section"
    )]
    pub target: Option<String>,

    /// Path to `Cargo.toml`
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to modify
    #[clap(short = 'p', long = "package", value_name = "PKGID")]
    pub pkgid: Option<String>,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Do not print any output in case of success.
    #[clap(long)]
    pub quiet: bool,

    /// Unstable (nightly-only) flags
    #[clap(
        short = 'Z',
        value_name = "FLAG",
        help_heading = "UNSTABLE",
        global = true,
        arg_enum
    )]
    pub unstable_features: Vec<UnstableOptions>,

    /// Git repository location
    ///
    /// Without any other information, cargo will use latest commit on the main branch.
    #[clap(long, value_name = "URI", help_heading = "UNSTABLE")]
    pub git: Option<String>,

    /// Git branch to download the crate from.
    #[clap(
        long,
        value_name = "BRANCH",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub branch: Option<String>,

    /// Git tag to download the crate from.
    #[clap(
        long,
        value_name = "TAG",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub tag: Option<String>,

    /// Git reference to download the crate from
    ///
    /// This is the catch all, handling hashes to named references in remote repositories.
    #[clap(
        long,
        value_name = "REV",
        help_heading = "UNSTABLE",
        requires = "git",
        group = "git-ref"
    )]
    pub rev: Option<String>,
}

impl Args {
    /// Get dependency section
    pub fn get_section(&self) -> Vec<String> {
        if self.dev {
            vec!["dev-dependencies".to_owned()]
        } else if self.build {
            vec!["build-dependencies".to_owned()]
        } else if let Some(ref target) = self.target {
            assert!(!target.is_empty(), "Target specification may not be empty");

            vec![
                "target".to_owned(),
                target.clone(),
                "dependencies".to_owned(),
            ]
        } else {
            vec!["dependencies".to_owned()]
        }
    }

    pub fn default_features(&self) -> Option<bool> {
        resolve_bool_arg(self.default_features, self.no_default_features)
    }

    /// Build dependencies from arguments
    pub fn parse_dependencies(&self, manifest: &LocalManifest) -> Result<Vec<Dependency>> {
        let workspace_members = workspace_members(self.manifest_path.as_deref())?;

        if self.crates.len() > 1 && self.git.is_some() {
            return Err(ErrorKind::MultipleCratesWithGitOrPathOrVers.into());
        }

        if self.crates.len() > 1 && self.rename.is_some() {
            return Err(ErrorKind::MultipleCratesWithRename.into());
        }

        if self.crates.len() > 1 && self.features.is_some() {
            return Err(ErrorKind::MultipleCratesWithFeatures.into());
        }

        self.crates
            .iter()
            .map(|crate_spec| {
                self.parse_single_dependency(manifest, crate_spec, &workspace_members)
            })
            .collect()
    }

    fn parse_single_dependency(
        &self,
        manifest: &LocalManifest,
        crate_spec: &str,
        workspace_members: &[Package],
    ) -> Result<Dependency> {
        let crate_spec = CrateSpec::resolve(crate_spec)?;
        let manifest_path = manifest.path.as_path();
        let registry_url = registry_url(&manifest_path, self.registry.as_deref())?;

        let mut dependency = match &crate_spec {
            CrateSpec::PkgId {
                name: _,
                version_req: Some(_),
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);
                // crate specifier includes a version (e.g. `docopt@0.8`)
                if let Some(ref url) = self.git {
                    let url = url.clone();
                    let version = dependency.version().unwrap().to_string();
                    return Err(ErrorKind::GitUrlWithVersion(url, version).into());
                }

                let features = get_features_from_registry(
                    &dependency.name,
                    dependency
                        .version()
                        .expect("version populated by `parse_as_version`"),
                    &registry_url,
                )?;
                dependency = dependency.set_available_features(features);

                dependency
            }
            CrateSpec::PkgId {
                name,
                version_req: None,
            } => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                if let Some(repo) = &self.git {
                    assert!(self.registry.is_none());
                    let features = get_manifest_from_url(repo)?
                        .map(|m| m.features())
                        .transpose()?
                        .unwrap_or_else(Vec::new);

                    dependency = dependency
                        .set_git(
                            repo,
                            self.branch.clone(),
                            self.tag.clone(),
                            self.rev.clone(),
                        )
                        .set_available_features(features);
                } else if let Some(version) =
                    manifest.get_dep_version(&self.get_section(), dependency.toml_key())
                {
                    let features =
                        get_features_from_registry(&dependency.name, &version, &registry_url)?;
                    dependency = dependency
                        .set_version(&version)
                        .set_available_features(features);
                } else if let Some(package) = workspace_members.iter().find(|p| p.name == *name) {
                    // Only special-case workspaces when the user doesn't provide any extra
                    // information, otherwise, trust the user.
                    dependency = dependency.set_path(
                        package
                            .manifest_path
                            .parent()
                            .expect("at least parent dir")
                            .as_std_path()
                            .to_owned(),
                    );
                    // dev-dependencies do not need the version populated
                    if !self.dev {
                        let op = "";
                        let v = format!("{op}{version}", op = op, version = package.version);
                        dependency = dependency.set_version(&v);
                    }
                } else {
                    let latest =
                        get_latest_dependency(name, false, &manifest_path, Some(&registry_url))?;
                    let op = "";
                    let v = format!(
                        "{op}{version}",
                        op = op,
                        // If version is unavailable `get_latest_dependency` must have
                        // returned `Err(FetchVersionError::GetVersion)`
                        version = latest.version().unwrap_or_else(|| unreachable!())
                    );
                    dependency = dependency
                        .set_version(&v)
                        .set_available_features(latest.available_features);
                }

                dependency
            }
            CrateSpec::Path(_) => {
                let mut dependency = crate_spec.to_dependency()?;
                dependency = self.populate_dependency(dependency);

                // dev-dependencies do not need the version populated
                if !self.dev {
                    let dep_path = dependency.path().map(ToOwned::to_owned);
                    if let Some(dep_path) = dep_path {
                        if let Some(package) = workspace_members.iter().find(|p| {
                            p.manifest_path.parent().map(|p| p.as_std_path())
                                == Some(dep_path.as_path())
                        }) {
                            let op = "";
                            let v = format!("{op}{version}", op = op, version = package.version);

                            dependency = dependency.set_version(&v);
                        }
                    }
                }
                dependency
            }
        };

        if let Some(registry) = &self.registry {
            dependency = dependency.set_registry(registry);
        }

        Ok(dependency)
    }

    fn populate_dependency(&self, mut dependency: Dependency) -> Dependency {
        let requested_features: Option<Vec<_>> = self.features.as_ref().map(|v| {
            v.iter()
                .flat_map(|s| s.split(' '))
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(|f| f.to_owned())
                .collect()
        });

        dependency = dependency
            .set_optional(self.optional())
            .set_default_features(self.default_features())
            .set_features(requested_features);

        if let Some(ref rename) = self.rename {
            dependency = dependency.set_rename(rename);
        }

        dependency
    }
}

impl Args {
    pub fn optional(&self) -> Option<bool> {
        resolve_bool_arg(self.optional, self.no_optional)
    }
}

#[cfg(test)]
impl Default for Args {
    fn default() -> Args {
        Args {
            crates: vec!["demo".to_owned()],
            rename: None,
            dev: false,
            build: false,
            git: None,
            branch: None,
            tag: None,
            rev: None,
            target: None,
            optional: false,
            no_optional: false,
            manifest_path: None,
            pkgid: None,
            features: None,
            no_default_features: false,
            default_features: false,
            quiet: false,
            offline: true,
            registry: None,
            unstable_features: vec![],
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
pub enum UnstableOptions {
    Git,
}

fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
    match (yes, no) {
        (true, false) => Some(true),
        (false, true) => Some(false),
        (false, false) => None,
        (_, _) => unreachable!("clap should make this impossible"),
    }
}

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

    #[test]
    fn verify_app() {
        use clap::IntoApp;
        Command::into_app().debug_assert()
    }
}
<|endoftext|>


<commit_before>use std::{
    error::Error as StdError,
    fmt,
    pin::Pin,
    task::{Context, Poll},
};

use bytes::Bytes;

use super::{BodySize, MessageBody, MessageBodyMapErr};
use crate::body;

/// A boxed message body with boxed errors.
pub struct BoxBody(BoxBodyInner);

enum BoxBodyInner {
    None(body::None),
    Bytes(Bytes),
    Stream(Pin<Box<dyn MessageBody<Error = Box<dyn StdError>>>>),
}

impl BoxBody {
    /// Same as `MessageBody::boxed`.
    ///
    /// If the body type to wrap is unknown or generic it is better to use [`MessageBody::boxed`] to
    /// avoid double boxing.
    #[inline]
    pub fn new<B>(body: B) -> Self
    where
        B: MessageBody + 'static,
    {
        match body.size() {
            BodySize::None => Self(BoxBodyInner::None(body::None)),
            _ => match body.try_into_bytes() {
                Ok(bytes) => Self(BoxBodyInner::Bytes(bytes)),
                Err(body) => {
                    let body = MessageBodyMapErr::new(body, Into::into);
                    Self(BoxBodyInner::Stream(Box::pin(body)))
                }
            },
        }
    }

    /// Returns a mutable pinned reference to the inner message body type.
    #[inline]
    pub fn as_pin_mut(&mut self) -> Pin<&mut Self> {
        Pin::new(self)
    }
}

impl fmt::Debug for BoxBody {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // TODO show BoxBodyInner
        f.write_str("BoxBody(dyn MessageBody)")
    }
}

impl MessageBody for BoxBody {
    type Error = Box<dyn StdError>;

    #[inline]
    fn size(&self) -> BodySize {
        match &self.0 {
            BoxBodyInner::None(none) => none.size(),
            BoxBodyInner::Bytes(bytes) => bytes.size(),
            BoxBodyInner::Stream(stream) => stream.size(),
        }
    }

    #[inline]
    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<Bytes, Self::Error>>> {
        match &mut self.0 {
            BoxBodyInner::None(_) => Poll::Ready(None),
            BoxBodyInner::Bytes(bytes) => Pin::new(bytes).poll_next(cx).map_err(Into::into),
            BoxBodyInner::Stream(stream) => Pin::new(stream).poll_next(cx),
        }
    }

    #[inline]
    fn try_into_bytes(self) -> Result<Bytes, Self> {
        match self.0 {
            BoxBodyInner::None(none) => Ok(none.try_into_bytes().unwrap()),
            BoxBodyInner::Bytes(bytes) => Ok(bytes.try_into_bytes().unwrap()),
            _ => Err(self),
        }
    }

    #[inline]
    fn boxed(self) -> BoxBody {
        self
    }
}

#[cfg(test)]
mod tests {

    use static_assertions::{assert_impl_all, assert_not_impl_all};

    use super::*;
    use crate::body::to_bytes;

    assert_impl_all!(BoxBody: MessageBody, fmt::Debug, Unpin);

    assert_not_impl_all!(BoxBody: Send, Sync, Unpin);

    #[actix_rt::test]
    async fn nested_boxed_body() {
        let body = Bytes::from_static(&[1, 2, 3]);
        let boxed_body = BoxBody::new(BoxBody::new(body));

        assert_eq!(
            to_bytes(boxed_body).await.unwrap(),
            Bytes::from(vec![1, 2, 3]),
        );
    }
}
<commit_msg>improve BoxBody Debug impl<commit_after>use std::{
    error::Error as StdError,
    fmt,
    pin::Pin,
    task::{Context, Poll},
};

use bytes::Bytes;

use super::{BodySize, MessageBody, MessageBodyMapErr};
use crate::body;

/// A boxed message body with boxed errors.
#[derive(Debug)]
pub struct BoxBody(BoxBodyInner);

enum BoxBodyInner {
    None(body::None),
    Bytes(Bytes),
    Stream(Pin<Box<dyn MessageBody<Error = Box<dyn StdError>>>>),
}

impl fmt::Debug for BoxBodyInner {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::None(arg0) => f.debug_tuple("None").field(arg0).finish(),
            Self::Bytes(arg0) => f.debug_tuple("Bytes").field(arg0).finish(),
            Self::Stream(_) => f.debug_tuple("Stream").field(&"dyn MessageBody").finish(),
        }
    }
}

impl BoxBody {
    /// Same as `MessageBody::boxed`.
    ///
    /// If the body type to wrap is unknown or generic it is better to use [`MessageBody::boxed`] to
    /// avoid double boxing.
    #[inline]
    pub fn new<B>(body: B) -> Self
    where
        B: MessageBody + 'static,
    {
        match body.size() {
            BodySize::None => Self(BoxBodyInner::None(body::None)),
            _ => match body.try_into_bytes() {
                Ok(bytes) => Self(BoxBodyInner::Bytes(bytes)),
                Err(body) => {
                    let body = MessageBodyMapErr::new(body, Into::into);
                    Self(BoxBodyInner::Stream(Box::pin(body)))
                }
            },
        }
    }

    /// Returns a mutable pinned reference to the inner message body type.
    #[inline]
    pub fn as_pin_mut(&mut self) -> Pin<&mut Self> {
        Pin::new(self)
    }
}

impl MessageBody for BoxBody {
    type Error = Box<dyn StdError>;

    #[inline]
    fn size(&self) -> BodySize {
        match &self.0 {
            BoxBodyInner::None(none) => none.size(),
            BoxBodyInner::Bytes(bytes) => bytes.size(),
            BoxBodyInner::Stream(stream) => stream.size(),
        }
    }

    #[inline]
    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<Bytes, Self::Error>>> {
        match &mut self.0 {
            BoxBodyInner::None(_) => Poll::Ready(None),
            BoxBodyInner::Bytes(bytes) => Pin::new(bytes).poll_next(cx).map_err(Into::into),
            BoxBodyInner::Stream(stream) => Pin::new(stream).poll_next(cx),
        }
    }

    #[inline]
    fn try_into_bytes(self) -> Result<Bytes, Self> {
        match self.0 {
            BoxBodyInner::None(none) => Ok(none.try_into_bytes().unwrap()),
            BoxBodyInner::Bytes(bytes) => Ok(bytes.try_into_bytes().unwrap()),
            _ => Err(self),
        }
    }

    #[inline]
    fn boxed(self) -> BoxBody {
        self
    }
}

#[cfg(test)]
mod tests {

    use static_assertions::{assert_impl_all, assert_not_impl_all};

    use super::*;
    use crate::body::to_bytes;

    assert_impl_all!(BoxBody: MessageBody, fmt::Debug, Unpin);

    assert_not_impl_all!(BoxBody: Send, Sync, Unpin);

    #[actix_rt::test]
    async fn nested_boxed_body() {
        let body = Bytes::from_static(&[1, 2, 3]);
        let boxed_body = BoxBody::new(BoxBody::new(body));

        assert_eq!(
            to_bytes(boxed_body).await.unwrap(),
            Bytes::from(vec![1, 2, 3]),
        );
    }
}
<|endoftext|>


<commit_before>use std::mem;

use ::{Vector3f, Point2f};
use bsdf::{BxDF, BxDFType, BSDF_SPECULAR, BSDF_REFLECTION};
use geometry::*;
use spectrum::Spectrum;
use na::{Dot, Norm, clamp};

/// Compute the reflection direction
pub fn reflect(wo: &Vector3f, n: &Vector3f) -> Vector3f {
    (-(*wo) + *n * 2.0 * wo.dot(n)).normalize()
}

/// Compute the refraction direction
pub fn refract(i: &Vector3f, n: &Vector3f, eta: f32) -> Option<Vector3f> {
    let cos_theta_i = n.dot(i);
    let sin2theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0);
    let sin2theta_t = eta * eta * sin2theta_i;

    if sin2theta_t >= 1.0 {
        None
    } else {
        let cos_theta_t = (1.0 - sin2theta_t).sqrt();
        Some(eta * -*i + (eta * cos_theta_i - cos_theta_t) * *n)
    }
}

/// Compute the Fresnel coefficient for dielectric materials
pub fn fr_dielectric(cos_theta_i: f32, eta_i: f32, eta_t: f32) -> f32 {
    let mut cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let (mut eta_i, mut eta_t) = (eta_i, eta_t);
    if cos_theta_i <= 0.0 {
        // If leaving the surface, swap the indices of refraction
        mem::swap(&mut eta_i, &mut eta_t);
        cos_theta_i = cos_theta_i.abs();
    }

    let sin_theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0).sqrt();
    let sin_theta_t = eta_i / eta_t * sin_theta_i;
    if sin_theta_t >= 1.0 {
        // Total internal reflection
        1.0
    } else {
        let cos_theta_t = (1.0 - sin_theta_t * sin_theta_t).max(0.0).sqrt();
        // Reflectance for parallel polarized light
        let r_parl = ((eta_t * cos_theta_i) - (eta_i * cos_theta_t)) /
                     ((eta_t * cos_theta_i) + (eta_i * cos_theta_t));
        // Reflectance for perpendicular polarized light
        let r_perp = ((eta_i * cos_theta_i) - (eta_t * cos_theta_t)) /
                     ((eta_i * cos_theta_i) + (eta_t * cos_theta_t));
        // Total reflectance for unpolarized light
        0.5 * (r_parl * r_parl + r_perp * r_perp)
    }
}

fn fr_conductor(cos_theta_i: f32, eta_i: &Spectrum, eta_t: &Spectrum, k: &Spectrum) -> Spectrum {
    let cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let eta = *eta_t / *eta_i;
    let eta_k = *k / *eta_i;

    let cos2_theta_i = cos_theta_i * cos_theta_i;
    let sin2_theta_i = 1.0 - cos2_theta_i;
    let eta2 = eta * eta;
    let eta_k2 = eta_k * eta_k;

    let t0 = eta2 - eta_k2 - sin2_theta_i;
    let a2plusb2 = (t0 * t0 + 4.0 * eta2 * eta_k2).sqrt();
    let t1 = a2plusb2 + cos2_theta_i;
    let a = (0.5 * (a2plusb2 + t0)).sqrt();
    let t2 = 2.0 * cos_theta_i * a;
    let r_s = (t1 - t2) / (t1 + t2);

    let t3 = cos2_theta_i * a2plusb2 + sin2_theta_i * sin2_theta_i;
    let t4 = t2 * sin2_theta_i;
    let r_p = r_s * (t3 - t4) / (t3 + t4);

    0.5 * (r_p + r_s)
}

/// Trait for Fresnel materials
pub trait Fresnel {
    fn evaluate(&self, cos_theta_i: f32) -> Spectrum;
}

impl Fresnel {
    pub fn conductor(eta_i: Spectrum, eta_t: Spectrum, k: Spectrum) -> FresnelConductor {
        FresnelConductor {
            eta_i: eta_i,
            eta_t: eta_t,
            k: k,
        }
    }

    pub fn dielectric(eta_i: f32, eta_t: f32) -> FresnelDielectric {
        FresnelDielectric {
            eta_i: eta_i,
            eta_t: eta_t,
        }
    }
}

/// Fresnel for conductor materials
pub struct FresnelConductor {
    eta_i: Spectrum,
    eta_t: Spectrum,
    k: Spectrum,
}

impl FresnelConductor {
    pub fn new(eta_i: Spectrum, eta_t: Spectrum, k: Spectrum) -> FresnelConductor {
        FresnelConductor {
            eta_i: eta_i,
            eta_t: eta_t,
            k: k,
        }
    }
}

impl Fresnel for FresnelConductor {
    fn evaluate(&self, cos_theta_i: f32) -> Spectrum {
        fr_conductor(cos_theta_i.abs(), &self.eta_i, &self.eta_t, &self.k)
    }
}

/// Fresnel for dielectric materials
pub struct FresnelDielectric {
    eta_i: f32,
    eta_t: f32,
}

impl Fresnel for FresnelDielectric {
    fn evaluate(&self, cos_theta_i: f32) -> Spectrum {
        Spectrum::grey(fr_dielectric(cos_theta_i.abs(), self.eta_i, self.eta_t))
    }
}

/// BRDF for perfect specular reflection
pub struct SpecularReflection {
    r: Spectrum,
    fresnel: Box<Fresnel + Send + Sync>,
}

impl SpecularReflection {
    pub fn new(r: Spectrum, fresnel: Box<Fresnel + Send + Sync>) -> SpecularReflection {
        SpecularReflection {
            r: r,
            fresnel: fresnel,
        }
    }
}

impl BxDF for SpecularReflection {
    fn f(&self, _wo: &Vector3f, _wi: &Vector3f) -> Spectrum {
        // The probability to call f() with the exact (wo, wi) for specular reflection is 0, so we
        // return black here. Use sample_f() instead.
        Spectrum::black()
    }

    fn sample_f(&self, wo: &Vector3f, _sample: &Point2f) -> (Spectrum, Vector3f, f32, BxDFType) {
        // There's only one possible wi for a given wo, so we always return it with a pdf of 1.
        let wi = Vector3f::new(-wo.x, -wo.y, wo.z);
        let spectrum = self.fresnel.evaluate(cos_theta(&wi)) * self.r / abs_cos_theta(&wi);
        (spectrum, wi, 1.0, BxDFType::empty())
    }

    fn pdf(&self, wo: &Vector3f, wi: &Vector3f) -> f32 {
        0.0
    }

    fn get_type(&self) -> BxDFType {
        BSDF_SPECULAR | BSDF_REFLECTION
    }
}
<commit_msg>Add bxdf for SpecularTransmission and FresnelSpecular<commit_after>use std::mem;

use ::{Vector3f, Point2f};
use bsdf::{BxDF, BxDFType, BSDF_SPECULAR, BSDF_REFLECTION, BSDF_TRANSMISSION};
use geometry::*;
use spectrum::Spectrum;
use na::{Dot, Norm, clamp};

/// Compute the reflection direction
pub fn reflect(wo: &Vector3f, n: &Vector3f) -> Vector3f {
    (-(*wo) + *n * 2.0 * wo.dot(n)).normalize()
}

/// Compute the refraction direction
pub fn refract(i: &Vector3f, n: &Vector3f, eta: f32) -> Option<Vector3f> {
    let cos_theta_i = n.dot(i);
    let sin2theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0);
    let sin2theta_t = eta * eta * sin2theta_i;

    if sin2theta_t >= 1.0 {
        None
    } else {
        let cos_theta_t = (1.0 - sin2theta_t).sqrt();
        Some(eta * -*i + (eta * cos_theta_i - cos_theta_t) * *n)
    }
}

/// Compute the Fresnel coefficient for dielectric materials
pub fn fr_dielectric(cos_theta_i: f32, eta_i: f32, eta_t: f32) -> f32 {
    let mut cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let (mut eta_i, mut eta_t) = (eta_i, eta_t);
    if cos_theta_i <= 0.0 {
        // If leaving the surface, swap the indices of refraction
        mem::swap(&mut eta_i, &mut eta_t);
        cos_theta_i = cos_theta_i.abs();
    }

    let sin_theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0).sqrt();
    let sin_theta_t = eta_i / eta_t * sin_theta_i;
    if sin_theta_t >= 1.0 {
        // Total internal reflection
        1.0
    } else {
        let cos_theta_t = (1.0 - sin_theta_t * sin_theta_t).max(0.0).sqrt();
        // Reflectance for parallel polarized light
        let r_parl = ((eta_t * cos_theta_i) - (eta_i * cos_theta_t)) /
                     ((eta_t * cos_theta_i) + (eta_i * cos_theta_t));
        // Reflectance for perpendicular polarized light
        let r_perp = ((eta_i * cos_theta_i) - (eta_t * cos_theta_t)) /
                     ((eta_i * cos_theta_i) + (eta_t * cos_theta_t));
        // Total reflectance for unpolarized light
        0.5 * (r_parl * r_parl + r_perp * r_perp)
    }
}

fn fr_conductor(cos_theta_i: f32, eta_i: &Spectrum, eta_t: &Spectrum, k: &Spectrum) -> Spectrum {
    let cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let eta = *eta_t / *eta_i;
    let eta_k = *k / *eta_i;

    let cos2_theta_i = cos_theta_i * cos_theta_i;
    let sin2_theta_i = 1.0 - cos2_theta_i;
    let eta2 = eta * eta;
    let eta_k2 = eta_k * eta_k;

    let t0 = eta2 - eta_k2 - sin2_theta_i;
    let a2plusb2 = (t0 * t0 + 4.0 * eta2 * eta_k2).sqrt();
    let t1 = a2plusb2 + cos2_theta_i;
    let a = (0.5 * (a2plusb2 + t0)).sqrt();
    let t2 = 2.0 * cos_theta_i * a;
    let r_s = (t1 - t2) / (t1 + t2);

    let t3 = cos2_theta_i * a2plusb2 + sin2_theta_i * sin2_theta_i;
    let t4 = t2 * sin2_theta_i;
    let r_p = r_s * (t3 - t4) / (t3 + t4);

    0.5 * (r_p + r_s)
}

/// Trait for Fresnel materials
pub trait Fresnel {
    fn evaluate(&self, cos_theta_i: f32) -> Spectrum;
}

impl Fresnel {
    pub fn conductor(eta_i: Spectrum, eta_t: Spectrum, k: Spectrum) -> FresnelConductor {
        FresnelConductor {
            eta_i: eta_i,
            eta_t: eta_t,
            k: k,
        }
    }

    pub fn dielectric(eta_i: f32, eta_t: f32) -> FresnelDielectric {
        FresnelDielectric {
            eta_i: eta_i,
            eta_t: eta_t,
        }
    }
}

/// Fresnel for conductor materials
pub struct FresnelConductor {
    eta_i: Spectrum,
    eta_t: Spectrum,
    k: Spectrum,
}

impl FresnelConductor {
    pub fn new(eta_i: Spectrum, eta_t: Spectrum, k: Spectrum) -> FresnelConductor {
        FresnelConductor {
            eta_i: eta_i,
            eta_t: eta_t,
            k: k,
        }
    }
}

impl Fresnel for FresnelConductor {
    fn evaluate(&self, cos_theta_i: f32) -> Spectrum {
        fr_conductor(cos_theta_i.abs(), &self.eta_i, &self.eta_t, &self.k)
    }
}

/// Fresnel for dielectric materials
pub struct FresnelDielectric {
    eta_i: f32,
    eta_t: f32,
}

impl Fresnel for FresnelDielectric {
    fn evaluate(&self, cos_theta_i: f32) -> Spectrum {
        Spectrum::grey(fr_dielectric(cos_theta_i.abs(), self.eta_i, self.eta_t))
    }
}

/// BRDF for perfect specular reflection
pub struct SpecularReflection {
    r: Spectrum,
    fresnel: Box<Fresnel + Send + Sync>,
}

impl SpecularReflection {
    pub fn new(r: Spectrum, fresnel: Box<Fresnel + Send + Sync>) -> SpecularReflection {
        SpecularReflection {
            r: r,
            fresnel: fresnel,
        }
    }
}

impl BxDF for SpecularReflection {
    fn f(&self, _wo: &Vector3f, _wi: &Vector3f) -> Spectrum {
        // The probability to call f() with the exact (wo, wi) for specular reflection is 0, so we
        // return black here. Use sample_f() instead.
        Spectrum::black()
    }

    fn sample_f(&self, wo: &Vector3f, _sample: &Point2f) -> (Spectrum, Vector3f, f32, BxDFType) {
        // There's only one possible wi for a given wo, so we always return it with a pdf of 1.
        let wi = Vector3f::new(-wo.x, -wo.y, wo.z);
        let spectrum = self.fresnel.evaluate(cos_theta(&wi)) * self.r / abs_cos_theta(&wi);
        (spectrum, wi, 1.0, BxDFType::empty())
    }

    fn pdf(&self, wo: &Vector3f, wi: &Vector3f) -> f32 {
        0.0
    }

    fn get_type(&self) -> BxDFType {
        BSDF_SPECULAR | BSDF_REFLECTION
    }
}

pub struct SpecularTransmission {
    t: Spectrum,
    eta_a: f32,
    eta_b: f32,
    fresnel: FresnelDielectric,
}

impl SpecularTransmission {
    pub fn new(t: Spectrum, eta_a: f32, eta_b: f32) -> SpecularTransmission {
        SpecularTransmission {
            t: t,
            eta_a: eta_a,
            eta_b: eta_b,
            fresnel: Fresnel::dielectric(eta_a, eta_b),
        }
    }
}

impl BxDF for SpecularTransmission {
    fn f(&self, _wo: &Vector3f, _wi: &Vector3f) -> Spectrum {
        // The probability to call f() with the exact (wo, wi) for specular transmission is 0, so we
        // return black here. Use sample_f() instead.
        Spectrum::black()
    }

    fn sample_f(&self, wo: &Vector3f, _sample: &Point2f) -> (Spectrum, Vector3f, f32, BxDFType) {
        // Figure out which $\eta$ is incident and which is transmitted
        let entering = cos_theta(wo) > 0.0;
        let eta_i = if entering { self.eta_a } else { self.eta_b };
        let eta_t = if entering { self.eta_b } else { self.eta_a };

        // Compute ray direction for specular transmission
        if let Some(wi) = refract(wo,
                                  &face_forward(&Vector3f::new(0.0, 0.0, 1.0), wo),
                                  eta_i / eta_t) {
            let mut ft = self.t * (Spectrum::white() - self.fresnel.evaluate(cos_theta(&wi)));

            // Account for non-symmetry with transmission to different medium TODO
            ft = ft * (eta_i * eta_i) / (eta_t * eta_t);
            info!("wo={}. wi={}, cos_theta(wo)={}, cos_theta(wi)={}, abs_cos_theta(wi)={}, ft={}",
                  wo,
                  wi,
                  cos_theta(wo),
                  cos_theta(&wi),
                  abs_cos_theta(&wi),
                  ft);

            return (ft / abs_cos_theta(&wi), wi, 1.0, BSDF_SPECULAR | BSDF_TRANSMISSION);
        } else {
            return (Spectrum::white(), Vector3f::new(0.0, 0.0, 0.0), 0.0, BxDFType::empty());
        }
    }

    fn pdf(&self, wo: &Vector3f, wi: &Vector3f) -> f32 {
        0.0
    }

    fn get_type(&self) -> BxDFType {
        BSDF_SPECULAR | BSDF_TRANSMISSION
    }
}

pub struct FresnelSpecular {
    r: Spectrum,
    t: Spectrum,
    eta_a: f32,
    eta_b: f32,
}

impl FresnelSpecular {
    pub fn new() -> FresnelSpecular {
        FresnelSpecular {
            r: Spectrum::white(),
            t: Spectrum::white(),
            eta_a: 1.0,
            eta_b: 1.5,
        }
    }
}

impl BxDF for FresnelSpecular {
    fn f(&self, _wo: &Vector3f, _wi: &Vector3f) -> Spectrum {
        // The probability to call f() with the exact (wo, wi) for specular reflection is 0, so we
        // return black here. Use sample_f() instead.
        Spectrum::black()
    }

    fn sample_f(&self, wo: &Vector3f, u: &Point2f) -> (Spectrum, Vector3f, f32, BxDFType) {
        let fr = fr_dielectric(cos_theta(wo), self.eta_a, self.eta_b);
        if u[0] < fr {
            // Compute specular reflection for FresnelSpecular

            // Compute perfect specular reflection direction
            let wi = Vector3f::new(-wo.x, -wo.y, wo.z);

            return (fr * self.r * abs_cos_theta(&wi), wi, fr, BSDF_SPECULAR | BSDF_REFLECTION);
        } else {
            // Compute specular transmission for FresnelSpecular

            // Figure out which $\eta$ is incident and which is transmitted
            let entering = cos_theta(wo) > 0.0;
            let eta_i = if entering { self.eta_a } else { self.eta_b };
            let eta_t = if entering { self.eta_b } else { self.eta_a };

            // Compute ray direction for specular transmission
            if let Some(wi) = refract(wo,
                                      &face_forward(&Vector3f::new(0.0, 0.0, 1.0), wo),
                                      eta_i / eta_t) {
                let ft = self.t * (1.0 - fr);

                // Account for non-symmetry with transmission to different medium
                // TODO
                //
                return (ft / abs_cos_theta(&wi), wi, 1.0 - fr, BSDF_SPECULAR | BSDF_TRANSMISSION);
            } else {
                return (Spectrum::white(), Vector3f::new(0.0, 0.0, 0.0), 0.0, BxDFType::empty());
            }
        }
    }

    fn pdf(&self, wo: &Vector3f, wi: &Vector3f) -> f32 {
        0.0
    }

    fn get_type(&self) -> BxDFType {
        BSDF_SPECULAR | BSDF_REFLECTION | BSDF_TRANSMISSION
    }
}

fn face_forward(v1: &Vector3f, v2: &Vector3f) -> Vector3f {
    if v1.dot(v2) < 0.0 { -(*v1) } else { *v1 }
}

#[test]
fn test_reflect() {
    let wo = Vector3f::new(-0.0137817357, -0.999056697, 0.0411854088);
    let n = Vector3f::new(-0.000777989568, 0.000739870942, 0.999999404);
    let wi = ::bsdf::reflect(&wo, &n);

    assert_relative_eq!(0.0137187857, wi.x);
    assert_relative_eq!(0.99911654, wi.y);
    assert_relative_eq!(0.0397284105, wi.z);
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/the-number-of-weak-characters-in-the-game/
pub fn number_of_weak_characters(properties: Vec<Vec<i32>>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        number_of_weak_characters(vec![vec![5, 5], vec![6, 3], vec![3, 6]])
    ); // 0
    println!(
        "{}",
        number_of_weak_characters(vec![vec![2, 2], vec![3, 3]])
    ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3]])
    ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3], vec![5, 5]])
    ); // 1
}
<commit_msg>Update problem 1996<commit_after>// https://leetcode.com/problems/the-number-of-weak-characters-in-the-game/
pub fn number_of_weak_characters(mut properties: Vec<Vec<i32>>) -> i32 {
    properties.sort_by_key(|v| (v[0], v[1]));
    let mut suffix_attack = vec![0; properties.len()];
    let mut suffix_defense = vec![0; properties.len()];
    for i in (0..properties.len()).rev() {
        let v = &properties[i];
        if i == properties.len() - 1 {
            suffix_attack[i] = v[0];
            suffix_defense[i] = v[1];
        } else {
            suffix_attack[i] = v[0].max(suffix_attack[i + 1]);
            suffix_defense[i] = v[1].max(suffix_defense[i + 1]);
        }
    }
    let mut answer = 0;
    println!("{:?}", properties);
    println!("{:?}", suffix_attack);
    println!("{:?}", suffix_defense);
    for i in 0..properties.len() - 1 {
        let attack = properties[i][0];
        let defense = properties[i][1];
        if attack < suffix_attack[i + 1] && defense < suffix_defense[i + 1] {
            answer += 1;
        }
    }
    answer
}

fn main() {
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![5, 5], vec![6, 3], vec![3, 6]])
    // ); // 0
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![2, 2], vec![3, 3]])
    // ); // 1
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3]])
    // ); // 1
    // println!(
    //     "{}",
    //     number_of_weak_characters(vec![vec![1, 5], vec![10, 4], vec![4, 3], vec![5, 5]])
    // ); // 1
    println!(
        "{}",
        number_of_weak_characters(vec![
            vec![7, 9],
            vec![10, 7],
            vec![6, 9],
            vec![10, 4],
            vec![7, 5],
            vec![7, 10]
        ])
    ); // 2
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/determine-if-two-events-have-conflict/
pub fn have_conflict(event1: Vec<String>, event2: Vec<String>) -> bool {
    todo!()
}

fn main() {
    println!(
        "{}",
        have_conflict(
            vec!["01:15".to_string(), "02:00".to_string()],
            vec!["02:00".to_string(), "03:00".to_string()]
        )
    ); // true
    println!(
        "{}",
        have_conflict(
            vec!["01:00".to_string(), "02:00".to_string()],
            vec!["01:20".to_string(), "03:00".to_string()]
        )
    ); // true
    println!(
        "{}",
        have_conflict(
            vec!["10:00".to_string(), "11:00".to_string()],
            vec!["14:00".to_string(), "15:00".to_string()]
        )
    ); // false
}
<commit_msg>Solve problem 2446<commit_after>// https://leetcode.com/problems/determine-if-two-events-have-conflict/
pub fn have_conflict(event1: Vec<String>, event2: Vec<String>) -> bool {
    fn to_minutes(time: String) -> i32 {
        let mut split = time.split(":");
        let hours: i32 = split.next().unwrap().parse().unwrap();
        let minutes: i32 = split.next().unwrap().parse().unwrap();
        (hours * 60) + minutes
    }

    let from_event1 = to_minutes(event1[0].to_string());
    let to_event1 = to_minutes(event1[1].to_string());
    let from_event2 = to_minutes(event2[0].to_string());
    let to_event2 = to_minutes(event2[1].to_string());

    from_event1 <= from_event2 && from_event2 <= to_event1
        || from_event2 <= from_event1 && from_event1 <= to_event2
}

fn main() {
    println!(
        "{}",
        have_conflict(
            vec!["01:15".to_string(), "02:00".to_string()],
            vec!["02:00".to_string(), "03:00".to_string()]
        )
    ); // true
    println!(
        "{}",
        have_conflict(
            vec!["02:00".to_string(), "03:00".to_string()],
            vec!["01:15".to_string(), "02:00".to_string()]
        )
    ); // true
    println!(
        "{}",
        have_conflict(
            vec!["01:00".to_string(), "02:00".to_string()],
            vec!["01:20".to_string(), "03:00".to_string()]
        )
    ); // true
    println!(
        "{}",
        have_conflict(
            vec!["10:00".to_string(), "11:00".to_string()],
            vec!["14:00".to_string(), "15:00".to_string()]
        )
    ); // false
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/words-within-two-edits-of-dictionary/
pub fn two_edit_words(queries: Vec<String>, dictionary: Vec<String>) -> Vec<String> {
    todo!()
}

fn main() {
    println!(
        "{:?}",
        two_edit_words(
            vec![
                "word".to_string(),
                "note".to_string(),
                "ants".to_string(),
                "wood".to_string()
            ],
            vec!["wood".to_string(), "joke".to_string(), "moat".to_string()]
        )
    ); // ["word","note","wood"]
    println!(
        "{:?}",
        two_edit_words(vec!["yes".to_string()], vec!["not".to_string()])
    ); // []
}
<commit_msg>Update problem 2452<commit_after>use std::collections::HashSet;

// https://leetcode.com/problems/words-within-two-edits-of-dictionary/
pub fn two_edit_words(queries: Vec<String>, dictionary: Vec<String>) -> Vec<String> {
    let mut answer: Vec<String> = vec![];
    let dictionary: HashSet<String> = dictionary.into_iter().collect();
    'outer: for query in queries.iter() {
        if dictionary.contains(query) {
            answer.push(query.clone());
            continue;
        }
        let mut bytes: Vec<u8> = query.as_bytes().into_iter().map(|a| *a).collect();
        for i in 0..bytes.len() {
            let tmp1 = bytes[i];
            for j in 0..26 {
                bytes[i] = j as u8 + 'a' as u8;
                let s = String::from_utf8(bytes.clone()).unwrap();
                if dictionary.contains(&s) {
                    answer.push(query.clone());
                    continue 'outer;
                }
                for k in i + 1..bytes.len() {
                    let tmp2 = bytes[k];
                    for l in 0..26 {
                        bytes[k] = l as u8 + 'a' as u8;
                        let s = String::from_utf8(bytes.clone()).unwrap();
                        if dictionary.contains(&s) {
                            answer.push(query.clone());
                            continue 'outer;
                        }
                    }
                    bytes[k] = tmp2;
                }
            }
            bytes[i] = tmp1;
        }
    }
    answer
}

fn main() {
    println!(
        "{:?}",
        two_edit_words(
            vec![
                "word".to_string(),
                "note".to_string(),
                "ants".to_string(),
                "wood".to_string()
            ],
            vec!["wood".to_string(), "joke".to_string(), "moat".to_string()]
        )
    ); // ["word","note","wood"]
    println!(
        "{:?}",
        two_edit_words(vec!["yes".to_string()], vec!["not".to_string()])
    ); // []
}
<|endoftext|>