diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj
new file mode 100644
index 00000000..6025fe64
--- /dev/null
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/BoringVector.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/UnitTest1.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/UnitTest1.cs
new file mode 100644
index 00000000..c7c4bbf1
--- /dev/null
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.Tests/UnitTest1.cs
@@ -0,0 +1,42 @@
+using System;
+using Xunit;
+
+namespace BoringVector.Tests
+{
+ public class UnitTest1
+ {
+ [Theory]
+ [InlineData(0, 0, 0)]
+ [InlineData(3, 4, 25)]
+ [InlineData(0, 1, 1)]
+ [InlineData(1, 1, 2)]
+ public void Test_SquareLength(double x, double y, double z)
+ {
+ Assert.Equal(new Vector(x, y).SquareLength(), z);
+ }
+
+ [Theory]
+ [InlineData(0, 0, 0, 0)]
+ [InlineData(3, 4, 25, 123)]
+ [InlineData(0, 1, 1, 10)]
+ [InlineData(1, 5, 1, 2)]
+ public void Test_Add(double x, double y, double a, double b)
+ {
+ var tmp = new Vector(x, y).Add(new Vector(a, b));
+ Assert.Equal(x + a, tmp.X);
+ Assert.Equal(y + b, tmp.Y);
+ }
+
+ [Theory]
+ [InlineData(0, 5, 0)]
+ [InlineData(4, 25, 123)]
+ [InlineData(1, 1, 10)]
+ [InlineData(5, 1, 2)]
+ public void Test_Scale(double x, double y, double k)
+ {
+ var tmp = new Vector(x, y).Scale(k);
+ Assert.Equal(x * k, tmp.X);
+ Assert.Equal(y * k, tmp.Y);
+ }
+ }
+}
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln
index ef06cdd5..33ed6758 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector.sln
@@ -1,9 +1,14 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2002
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31229.75
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BoringVector", "BoringVector\BoringVector.csproj", "{7B438112-6A12-47BC-B494-FF8850924783}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BoringVector", "BoringVector\BoringVector.csproj", "{7B438112-6A12-47BC-B494-FF8850924783}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BoringVector.Tests", "BoringVector.Tests\BoringVector.Tests.csproj", "{F43CA846-71FE-4428-BAD4-A4ADDBF9A784}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7B438112-6A12-47BC-B494-FF8850924783} = {7B438112-6A12-47BC-B494-FF8850924783}
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,6 +20,10 @@ Global
{7B438112-6A12-47BC-B494-FF8850924783}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B438112-6A12-47BC-B494-FF8850924783}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B438112-6A12-47BC-B494-FF8850924783}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F43CA846-71FE-4428-BAD4-A4ADDBF9A784}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F43CA846-71FE-4428-BAD4-A4ADDBF9A784}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F43CA846-71FE-4428-BAD4-A4ADDBF9A784}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F43CA846-71FE-4428-BAD4-A4ADDBF9A784}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs
index f5873162..ace88470 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Program.cs
@@ -1,4 +1,6 @@
using System;
+using System.Runtime.CompilerServices;
+[assembly: InternalsVisibleTo("BoringVector.Tests")]
namespace BoringVector
{
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
index bb9db585..b9bc95cc 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/Vector.cs
@@ -7,12 +7,16 @@ namespace BoringVector
/*
Реализуй структуру Vector - см. комментарии внутри нее.
*/
-
+ ///
+ /// Структура вектора в двумерном пространстве.
+ ///
internal struct Vector
{
- /*
- Vector задается парой вещественных координат X и Y.
- */
+ ///
+ /// Координаты вектора X и Y.
+ ///
+ public readonly double X;
+ public readonly double Y;
/*
@@ -23,32 +27,72 @@ internal struct Vector
- скалярное произведение
- векторное произведение (= площадь параллелограмма)
*/
-
+ ///
+ /// Констурктор вектора по координатам X и Y.
+ ///
+ /// Координата вектора по Ox.
+ /// Координата вектора по Oy.
+ public Vector(double x, double y)
+ {
+ X = x;
+ Y = y;
+ }
+ ///
+ /// Возвращает квадрат длины вектора.
+ ///
+ /// Вещественное число.
public double SquareLength()
{
- throw new NotImplementedException();
+ return X * X + Y * Y;
}
+ ///
+ /// Прибавление другого вектора к исходному.
+ ///
+ /// Вектор.
+ /// Результирующий вектор.
public Vector Add(Vector v)
{
- throw new NotImplementedException();
+ return new Vector(X + v.X, Y + v.Y);
}
+ ///
+ /// Умножение вектора на коэффициент k.
+ ///
+ /// Коэффициент.
+ /// Результирующий вектор.
public Vector Scale(double k)
{
- throw new NotImplementedException();
+ return new Vector(k * X, k * Y);
}
+ ///
+ /// Скалярное произведение векторов.
+ ///
+ /// Вектор, с которым происхоит умножение.
+ /// Вещественное число.
public double DotProduct(Vector v)
{
- throw new NotImplementedException();
+ return X * v.X + Y * v.Y;
}
+ ///
+ /// Векторное произведение векторов.
+ ///
+ /// Вектор, с которым происхоит умножение.
+ /// Вещественное число.
public double CrossProduct(Vector v)
{
- throw new NotImplementedException();
+ return X * v.Y - Y * v.X;
}
/*
Переопредели ниже метод ToString - пусть выводит (X; Y)
*/
-
+ ///
+ /// Вектор в формате (X; Y).
+ ///
+ /// Строка.
+ public override string ToString()
+ {
+ return String.Format("({0}; {1})", X, Y);
+ }
#region operators
/*
@@ -57,6 +101,76 @@ public double CrossProduct(Vector v)
- k * v, v * k, v / k
- +v, -v
*/
+ ///
+ /// Вычисление суммы векторов.
+ ///
+ /// Первый вектор.
+ /// Второй вектор.
+ /// Результирующий вектор от суммы.
+ public static Vector operator +(Vector v, Vector u)
+ {
+ return v.Add(u);
+ }
+ ///
+ /// Вычисление разности векторов.
+ ///
+ /// Первый вектор.
+ /// Второй вектор.
+ /// Результирующий вектор от разности.
+ public static Vector operator -(Vector v, Vector u)
+ {
+ return v.Add(u.Scale(-1));
+ }
+ ///
+ /// Умножение вектора на коэффициент.
+ ///
+ /// Исходный вектор.
+ /// Коэффициент.
+ /// Результирующий вектор от уможения.
+ public static Vector operator *(Vector v, double k)
+ {
+ return v.Scale(k);
+ }
+ ///
+ /// Умножение вектора на коэффициент.
+ ///
+ /// Коэффициент.
+ /// Исходный вектор.
+ /// Результирующий вектор от уможения.
+ public static Vector operator *(double k, Vector v)
+ {
+ return v.Scale(k);
+ }
+ ///
+ /// Деление вектора на коэффициент.
+ ///
+ /// Исходный вектор.
+ /// Коэффициент.
+ /// Результирующий вектор от деления.
+ public static Vector operator /(Vector v, double k)
+ {
+ if (k == 0)
+ throw new DivideByZeroException();
+ return v.Scale(1 / k);
+ }
+ ///
+ /// Возвращает вектор.
+ ///
+ /// Исходный вектор.
+ /// Исходынй вектор.
+ public static Vector operator +(Vector v)
+ {
+ return v;
+ }
+ ///
+ /// Возвращает противоположный вектор.
+ ///
+ /// Исходынй вектор.
+ /// Противоположный вектор.
+ public static Vector operator -(Vector v)
+ {
+ return v.Scale(-1);
+ }
#endregion
}
diff --git a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
index 525be40f..2caea2e9 100644
--- a/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
+++ b/course-2021-1/exercises/03-boring-vector/BoringVector/BoringVector/VectorExtensions.cs
@@ -1,4 +1,6 @@
-namespace BoringVector
+using System;
+
+namespace BoringVector
{
/*
Здесь тебе нужно написать класс с методами-расширениями структуры Vector:
@@ -7,4 +9,77 @@
- GetAngleBetween: возвращает угол между двумя векторами в радианах. Примечание: нулевой вектор сонаправлен любому другому.
- GetRelation: возвращает значение перечесления VectorRelation(General, Parallel, Orthogonal) - отношение между двумя векторами("общий случай", параллельны, перпендикулярны). Перечисление задавать тоже тебе)
*/
+
+ ///
+ /// Расширяющий класс Vector.
+ ///
+ internal static class VectorExtensions
+ {
+ ///
+ /// Эпсилон.
+ ///
+ private const double eps = 1e-6;
+ ///
+ /// Перечисления - отношение между двумя векторами("общий случай", параллельны, перпендикулярны).
+ ///
+ internal enum VectorRelation
+ {
+ General, Parallel, Orthogonal
+ }
+ ///
+ /// Проверяет, является ли вектор нулевым.
+ ///
+ /// Исходный вектор.
+ /// True, если вектор нулевой, иначе False
+ public static bool IsZero(this Vector v)
+ {
+ return Math.Abs(v.X) < eps && Math.Abs(v.Y) < eps;
+ }
+ ///
+ /// Нормализует вектор (если он не нулевой).
+ ///
+ /// Исходный вектор.
+ /// Нормализованный вектор.
+ public static Vector Normalize(this Vector v)
+ {
+ if (IsZero(v))
+ return v;
+ return v / Math.Sqrt(v.SquareLength());
+ }
+ ///
+ /// Вычисление угла между векторами.
+ ///
+ /// Первый вектор.
+ /// Второй.
+ /// Угол между векторами в радианах от 0 до PI.
+ public static double GetAngleBetween(this Vector v, Vector u)
+ {
+ if (IsZero(v) || IsZero(u))
+ {
+ return 0;
+ }
+
+ return Math.Acos(Normalize(v).DotProduct(Normalize(u)));
+ }
+ ///
+ /// Вычисление отношения между двумя заданными векторами.
+ ///
+ /// Первый вектор.
+ /// Второй вектор.
+ /// Отношение между двумя векторами("общий случай", параллельны, перпендикулярны).
+ public static VectorRelation GetRelation(this Vector v, Vector u)
+ {
+ var ang = GetAngleBetween(v, u);
+
+ if (ang < eps || Math.PI - ang < eps)
+ {
+ return VectorRelation.Parallel;
+ }
+ if (Math.Abs(Math.PI / 2 - ang) < eps)
+ {
+ return VectorRelation.Orthogonal;
+ }
+ return VectorRelation.General;
+ }
+ }
}