Решение на (Floating) Points and Vectors от Николай Данаилов

Обратно към всички решения

Към профила на Николай Данаилов

Резултати

  • 20 точки от тестове
  • 0 бонус точки
  • 20 точки общо
  • 15 успешни тест(а)
  • 0 неуспешни тест(а)

Код

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::BitXor;
fn float_equal(a: f64, b: f64) -> bool {
(a - b).abs() < std::f64::EPSILON
}
#[derive(Debug, Clone, Copy)]
pub struct Point(f64, f64, f64);
impl Point {
pub fn new(x: f64, y: f64, z: f64) -> Self {
Point(x, y, z)
}
}
impl PartialEq for Point {
fn eq(&self, other: &Point) -> bool {
float_equal(self.0, other.0)
&& float_equal(self.1, other.1)
&& float_equal(self.2, other.2)
}
}
impl Sub<Point> for Point {
type Output = Vector;
fn sub(self, other: Point) -> Vector {
Vector(self.0 - other.0, self.1 - other.1, self.2 - other.2)
}
}
impl Add<Vector> for Point {
type Output = Point;
fn add(self, other: Vector) -> Point {
Point(self.0 + other.0, self.1 + other.1, self.2 + other.2)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Vector(f64, f64, f64);
impl Vector {
pub fn new(x: f64, y: f64, z: f64) -> Self {
Vector(x, y, z)
}
pub fn is_zero(&self) -> bool {
float_equal(self.0, 0.0)
&& float_equal(self.1, 0.0)
&& float_equal(self.2, 0.0)
}
pub fn norm(&self) -> f64 {
(self.0.powi(2) + self.1.powi(2) + self.2.powi(2)).sqrt()
}
}
impl PartialEq for Vector {
fn eq(&self, other: &Vector) -> bool {
float_equal(self.0, other.0)
&& float_equal(self.1, other.1)
&& float_equal(self.2, other.2)
}
}
impl Add<Vector> for Vector {
type Output = Vector;
fn add(self, other: Vector) -> Vector {
Vector(self.0 + other.0, self.1 + other.1, self.2 + other.2)
}
}
impl Mul<Vector> for Vector {
type Output = f64;
fn mul(self, other: Vector) -> f64 {
self.0 * other.0 + self.1 * other.1 + self.2 * other.2
}
}
impl BitXor<Vector> for Vector {
type Output = Vector;
fn bitxor(self, other: Vector) -> Vector {
Vector(self.1 * other.2 - self.2 * other.1,
self.2 * other.0 - self.0 * other.2,
self.0 * other.1 - self.1 * other.0)
}
}
impl Mul<Vector> for f64 {
type Output = Vector;
fn mul(self, other: Vector) -> Vector {
Vector(self * other.0, self * other.1, self * other.2)
}
}
#[derive(Debug)]
pub struct Line {
p1: Point,
p2: Point,
v: Vector
}
impl Line {
/// Конструиране на линия през две точки, които минават през нея. Две различни точки са
/// достатъчни, за да дефинират еднозначно линия.
///
/// Можете да получите точка и вектор, като извадите едната от другата точка.
///
/// Ако точките са една и съща, очакваме да върнете None.
///
pub fn from_pp(p1: Point, p2: Point) -> Option<Self> {
if p1 == p2 {
None
}
else {
Some(Line {
p1: p1,
p2: p2,
v: p2 - p1
})
}
}
/// Конструиране на линия през точка за начало, и вектор, който определя посоката. Стига
/// вектора да е ненулев, това е достатъчно, за да дефинира еднозначно линия.
///
/// Може да получите две точки, като съберете дадената с вектора.
///
/// Ако вектора е нулев, очакваме да върнете None.
///
pub fn from_pv(p: Point, v: Vector) -> Option<Self> {
if v.is_zero() {
None
}
else {
Some(Line {
p1: p,
p2: p + v,
v: v
})
}
}
}
impl Line {
pub fn distance(&self, target: Point) -> f64 {
((target - self.p1) ^ self.v).norm() / self.v.norm()
}
}
impl PartialEq<Line> for Line {
fn eq(&self, other: &Line) -> bool {
float_equal(self.distance(other.p1), 0.0)
&& float_equal(self.distance(other.p2), 0.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compare_floats() {
assert!(float_equal(0.3, 0.30000000000000004));
assert!(float_equal(0.1, 0.1));
}
#[test]
fn test_norm() {
let v = Vector::new(1.0, 1.0, 1.0);
assert_eq!(v.norm(), 3f64.sqrt());
let zero_v = Vector::new(0.0, 0.0, 0.0);
assert_eq!(zero_v.norm(), 0.0);
}
#[test]
fn test_line_from_points() {
let p1 = Point::new(0.0, 0.0, 0.0);
let p2 = Point::new(1.5, 2.5, 3.5);
let line = Line::from_pp(p1, p2).unwrap();
assert_eq!(line.p1, p1);
assert_eq!(line.p2, p2);
assert_eq!(line.v, Vector::new(1.5, 2.5, 3.5));
}
#[test]
fn test_line_from_vector_and_point() {
let p = Point::new(0.0, 0.0, 0.0);
let v = Vector::new(1.0, 2.0, 3.0);
let line = Line::from_pv(p, v).unwrap();
assert_eq!(line.p1, p);
assert_eq!(line.p2, Point::new(1.0, 2.0, 3.0));
assert_eq!(line.v, v);
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20190123-22631-ifdm3q/solution)
    Finished dev [unoptimized + debuginfo] target(s) in 4.91s
     Running target/debug/deps/solution-2e785d603b538f71

running 4 tests
test tests::test_compare_floats ... ok
test tests::test_line_from_points ... ok
test tests::test_line_from_vector_and_point ... ok
test tests::test_norm ... ok

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-29808948fb50ed3a

running 15 tests
test solution_test::test_equailty_symmetry ... ok
test solution_test::test_equality_basic ... ok
test solution_test::test_equality_floating ... ok
test solution_test::test_line_constructors ... ok
test solution_test::test_line_equality_by_points ... ok
test solution_test::test_line_equality_by_points_and_vectors ... ok
test solution_test::test_line_equality_by_vectors ... ok
test solution_test::test_line_validity ... ok
test solution_test::test_number_by_vector ... ok
test solution_test::test_number_vector_multiplication_with_precision ... ok
test solution_test::test_point_distance ... ok
test solution_test::test_points_minus_points ... ok
test solution_test::test_points_plus_vectors ... ok
test solution_test::test_vector_by_vector ... ok
test solution_test::test_vector_by_vector_cross ... ok

test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests solution

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

История (1 версия и 1 коментар)

Николай качи първо решение на 26.11.2018 15:40 (преди почти 7 години)

Добра работа, разумно решение. Добре е, че си написал и тестове, макар че можеше да са малко по-интересни -- особено за равенството на прави, има доста интересни тестове, които могат да ти валидират assumption-ите -- Line.from_pp(p1, p2) == Line.from_pp(p2, p1) примерно?

Може да хвърлиш едно око на пълните тестове тук, за вдъхновение: https://github.com/fmi/rust-homework/blob/master/02/test_full.rs. Правилния комплект тестове могат да ти дадат доста увереност в това, че имаш правилно решение, особено като става въпрос за математически формули.