From 2615656df21fcff27534d9aa4c4a995f0cb3f5af Mon Sep 17 00:00:00 2001 From: igorigrik Date: Sun, 29 Sep 2024 12:04:42 +0300 Subject: [PATCH] Initial commit --- .gitignore | 4 + Demo/Demo.csproj | 13 ++++ Demo/Form1.Designer.cs | 64 +++++++++++++++ Demo/Form1.cs | 90 ++++++++++++++++++++++ Demo/Form1.resx | 60 +++++++++++++++ Demo/Program.cs | 35 +++++++++ README.md | 8 +- YMath.sln | 31 ++++++++ YMath/Camera.cs | 47 +++++++++++ YMath/CoordSystem.cs | 39 ++++++++++ YMath/Matrix.cs | 141 +++++++++++++++++++++++++++++++++ YMath/Projector.cs | 39 ++++++++++ YMath/Vector.cs | 171 +++++++++++++++++++++++++++++++++++++++++ YMath/YMath.7z | Bin 0 -> 2944 bytes YMath/YMath.csproj | 10 +++ 15 files changed, 750 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 Demo/Demo.csproj create mode 100644 Demo/Form1.Designer.cs create mode 100644 Demo/Form1.cs create mode 100644 Demo/Form1.resx create mode 100644 Demo/Program.cs create mode 100644 YMath.sln create mode 100644 YMath/Camera.cs create mode 100644 YMath/CoordSystem.cs create mode 100644 YMath/Matrix.cs create mode 100644 YMath/Projector.cs create mode 100644 YMath/Vector.cs create mode 100644 YMath/YMath.7z create mode 100644 YMath/YMath.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85d61f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vs +**/bin/** +**/obj/** +*.user \ No newline at end of file diff --git a/Demo/Demo.csproj b/Demo/Demo.csproj new file mode 100644 index 0000000..9c03f60 --- /dev/null +++ b/Demo/Demo.csproj @@ -0,0 +1,13 @@ + + + + WinExe + net5.0-windows + true + + + + + + + \ No newline at end of file diff --git a/Demo/Form1.Designer.cs b/Demo/Form1.Designer.cs new file mode 100644 index 0000000..9cfbb3d --- /dev/null +++ b/Demo/Form1.Designer.cs @@ -0,0 +1,64 @@ + +namespace Demo +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBox1.Location = new System.Drawing.Point(0, 0); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(800, 450); + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click); + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.pictureBox1); + this.Name = "Form1"; + this.Text = "Form1"; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + } +} + diff --git a/Demo/Form1.cs b/Demo/Form1.cs new file mode 100644 index 0000000..f343f4d --- /dev/null +++ b/Demo/Form1.cs @@ -0,0 +1,90 @@ +using YMath; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Demo +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + } + + private void pictureBox1_Click(object sender, EventArgs e) + { + /*var g = pictureBox1.CreateGraphics(); + g.SmoothingMode = SmoothingMode.HighQuality; + var pen = new Pen(Brushes.Black, 2); + var rect = CubePoints(100.0, 2); + DrawLines(g, pen, rect);*/ + }/* + + // [-1; 1] -> [0; width] + private static Vector[] RelativeToAbsolute(Vector[] points, int width, int height) + { + return points.Select(p => new Vector( + (p[0] + 1) / 2 * width, + (p[1] + 1) / 2 * height)) + .ToArray(); + } + + private static void DrawLines(Graphics g, Pen pen, Line[] lines) + { + foreach (var line in lines) + g.DrawLine(pen, + new PointF((float)line.Start[0], (float)line.End[1]), + new PointF((float)line.Start[0], (float)line.End[1])); + } + + public struct Line + { + public Line(Vector start, Vector end) + { + Start = start; + End = end; + } + + public Vector Start { get; set; } + public Vector End { get; set; } + } + + public static Line[] Cube(int nDimensions) + { + if (nDimensions == 0) + return new Vector[] { new Vector(0) }; + + var result = new List(); + var offset = new Vector(nDimensions); + offset[nDimensions - 1] = 1; + var face /*боже*//* = Cube(nDimensions - 1); + result.AddRange(face.Select(p => p + offset)); + result.AddRange(face.Select(p => p - offset)); + + } + + public static Vector[] CubePoints(double size, int nDimensions) + { + int n = 1 << nDimensions; + if (nDimensions >= 32) + throw new ArgumentException("Fuck yourself"); + var result = new Vector[n]; + for (int i = 0; i < n; i++) + { + var vec = new Vector(nDimensions); + for (int j = 0; j < nDimensions; j++) + vec[j] = ((i >> j) & 1) - 0.5; + result[i] = vec; + } + return result; + }*/ + } +} diff --git a/Demo/Form1.resx b/Demo/Form1.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/Demo/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Demo/Program.cs b/Demo/Program.cs new file mode 100644 index 0000000..4007da9 --- /dev/null +++ b/Demo/Program.cs @@ -0,0 +1,35 @@ +using YMath; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Demo +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + + Projector p = new Projector( + new Camera(1), + new CoordSystem(new Vector(), Matrix.Ident(4))); + var point = p.Project(new Vector(1, 1, 1, 2)); + + + + + + Application.Run(new Form1()); + } + } +} diff --git a/README.md b/README.md index b63408d..9a61398 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ -# YMath-Demo +# YMath -Some basic math (matrices, vectors) \ No newline at end of file +Some basic math + +`YMath` - the Y-Math library + +`Demo` - the demo project, YMath usage example \ No newline at end of file diff --git a/YMath.sln b/YMath.sln new file mode 100644 index 0000000..a505dae --- /dev/null +++ b/YMath.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30711.63 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YMath", "YMath\YMath.csproj", "{33638CEC-2BD2-4B91-A1CB-0383F7E429BE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{CE175AF3-5242-4178-BB97-54956FE958D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33638CEC-2BD2-4B91-A1CB-0383F7E429BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33638CEC-2BD2-4B91-A1CB-0383F7E429BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33638CEC-2BD2-4B91-A1CB-0383F7E429BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33638CEC-2BD2-4B91-A1CB-0383F7E429BE}.Release|Any CPU.Build.0 = Release|Any CPU + {CE175AF3-5242-4178-BB97-54956FE958D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE175AF3-5242-4178-BB97-54956FE958D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE175AF3-5242-4178-BB97-54956FE958D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE175AF3-5242-4178-BB97-54956FE958D8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C03EF0F0-151C-44B0-A13B-96F2820629C7} + EndGlobalSection +EndGlobal diff --git a/YMath/Camera.cs b/YMath/Camera.cs new file mode 100644 index 0000000..0d17255 --- /dev/null +++ b/YMath/Camera.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace YMath +{ + + /// + /// Представляет камеру, выполняющую преобразование между трёхмерны пространством объектом и двумерной плоскостью изображения + /// + public class Camera + { + public Camera(double t) + { + T = t; + } + /// + /// Коэффициент функции преобразования камеры + /// + public double T { get; set; } + + public Vector WorldToImage(Vector worldPoint) + { + int imageOrder = worldPoint.Dimensions - 1; + var result = new Vector(imageOrder); + double last = worldPoint[worldPoint.Dimensions - 1]; + + for (int i = 0; i < imageOrder; i++) + result[i] = worldPoint[i] * T / last; + + return result; + } + + public Vector ImageToWorld(Vector imagePoint) + { + int worldOrder = imagePoint.Dimensions + 1; + var result = new Vector(worldOrder); + + for (int i = 0; i < worldOrder-1; i++) + result[i] = imagePoint[i] * 1 / T; + result[worldOrder - 1] = 1; + + return result; + } + } +} diff --git a/YMath/CoordSystem.cs b/YMath/CoordSystem.cs new file mode 100644 index 0000000..59dd2c3 --- /dev/null +++ b/YMath/CoordSystem.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace YMath +{ + /// + /// Представляет систему координат, имеющую заданные линейные и угловые смещения + /// + public class CoordSystem + { + public CoordSystem(Vector shift, Matrix rotationMatrix) + { + Shift = shift; + RotationMatrix = rotationMatrix; + } + + /// + /// Вектор линейных смещений + /// + public Vector Shift { get; set; } + + /// + /// Матрица угловых смещений + /// + public Matrix RotationMatrix { get; set; } + + public Vector LocalToWorld(Vector localPoint) + { + return RotationMatrix * localPoint + Shift; + } + + public Vector WorldToLocal(Vector worldPoint) + { + return RotationMatrix.GetTranspose() * (worldPoint - Shift); + } + } +} diff --git a/YMath/Matrix.cs b/YMath/Matrix.cs new file mode 100644 index 0000000..03ba9f5 --- /dev/null +++ b/YMath/Matrix.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace YMath +{ + /// + /// Представляет матрицу с определённым количеством строк и столбцов + /// + public class Matrix + { + /// + /// Создание матрицы с заданным числом строк и столбцов + /// + /// + /// + public Matrix(int rows, int coluumns) + { + Data = new double[coluumns , rows]; + } + + public Matrix(int rows, int coluumns, double[] values) + : this(rows, coluumns) + { + if (values.Length != Rows * Columns) + throw new InvalidCastException("values array length is invalid"); + for (int i = 0; i < values.Length; i++) + this[i / Columns, i % Columns] = values[i]; + } + + + protected double[,] Data { get; set; } + public int Rows { get { return Data.GetLength(1); } } + public int Columns { get { return Data.GetLength(0); } } + + public double this[int row, int column] + { + get { return Data[column, row]; } + set { Data[column, row] = value; } + } + + public override string ToString() + { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < Rows; i++) + { + for (int j = 0; j < Columns; j++) + { + string s = string.Format("{0:0.00}", this[i, j]); + s = s.PadRight(7); + result.Append(s); + } + result.AppendLine(); + } + return result.ToString(); + } + + public void Add(Matrix other) + { + int rows = Math.Min(Rows, other.Rows); + int cols = Math.Min(Columns, other.Columns); + for(int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + this[i, j] += other[i, j]; + } + + /// + /// Returns the negated version of the matrix + /// + public static Matrix operator -(Matrix matrix) + { + Matrix result = new Matrix(matrix.Rows, matrix.Columns); + for (int i = 0; i < matrix.Rows; i++) + for (int j = 0; j < matrix.Columns; j++) + result[i, j] = -matrix[i, j]; + return result; + } + + + public static Matrix operator +(Matrix left, Matrix right) + { + Matrix result = new Matrix( + Math.Max(left.Rows, right.Rows), + Math.Max(left.Columns, right.Columns)); + result.Add(left); + result.Add(right); + return result; + } + + public static Matrix operator -(Matrix left, Matrix right) + { + Matrix result = new Matrix( + Math.Max(left.Rows, right.Rows), + Math.Max(left.Columns, right.Columns)); + result.Add(left); + result.Add(-right); + return result; + } + + public static Matrix operator *(Matrix left, Matrix right) + { + if(left.Columns != right.Rows) + throw new ArgumentException("Left.Columns != Right.Rows"); + Matrix result = new Matrix(left.Rows, right.Columns); + for (int i = 0; i < result.Rows; i++) + for (int j = 0; j < result.Columns; j++) + for (int r = 0; r < left.Columns; r++) + result[i, j] += left[i, r] * right[r, j]; + return result; + } + + public Matrix GetTranspose() + { + Matrix result = new Matrix(Columns, Rows); + for (int i = 0; i < Columns; i++) + for (int j = 0; j < Rows; j++) + result[j, i] = this[i, j]; + return result; + } + + public bool IsInvalid() + { + foreach (double f in Data) + if (double.IsNaN(f) || double.IsInfinity(f)) + return true; + return false; + } + + /// + /// Returns n-dimensional identity matrix + /// + public static Matrix Ident(int nDimensions) + { + var result = new Matrix(nDimensions, nDimensions); + for (int i = 0; i < nDimensions; i++) + result[i, i] = 1; + return result; + } + } +} diff --git a/YMath/Projector.cs b/YMath/Projector.cs new file mode 100644 index 0000000..c27ec31 --- /dev/null +++ b/YMath/Projector.cs @@ -0,0 +1,39 @@ +using YMath; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace YMath +{ + public class Projector + { + public Projector(Camera camera, CoordSystem coordSystem) + { + Camera = camera; + CoordSystem = coordSystem; + } + + /// + /// The coordinate system containing the points + /// + public CoordSystem CoordSystem { get; set; } + + /// + /// A camera building the image + /// + public Camera Camera { get; set; } + + /// + /// Projects the given point + /// + /// The N-1 dimensional point + public Vector Project(Vector point) + { + point = CoordSystem.LocalToWorld(point); + point = Camera.WorldToImage(point); + return point; + } + } +} diff --git a/YMath/Vector.cs b/YMath/Vector.cs new file mode 100644 index 0000000..47f27f3 --- /dev/null +++ b/YMath/Vector.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace YMath +{ + /// + /// Представляет вектор-столбец произвольной размерности + /// + public class Vector : Matrix + { + /// + /// Создаёт вектор-столбец размерности n + /// + /// + public Vector(int n) + : base(n, 1) + { + } + + /// + /// Создаёт вектор-столбец размерности n и с указанными значениями + /// + public Vector(int n, double[] values) + : base(n, 1, values) + { + } + + /// + /// Создаёт вектор-столбец с указанными значениями + /// + public Vector(params double[] values) + : base(values.Length, 1, values) + { + } + + public double this[int row] + { + get { return this[row, 0]; } + set { this[row, 0] = value; } + } + + /// + /// Возвращает размерность вектора + /// + public int Dimensions { get { return Rows; } } + + public override string ToString() + { + List vals = new List(); + for (int i = 0; i < Dimensions; i++) + vals.Add(string.Format("{0:0.00}", this[i])); + return "(" + string.Join("; ", vals.ToArray()) + ")"; + } + + /// + /// Представление матрицы как вектора + /// + public static Vector FromMatrix(Matrix m) + { + if (m.Columns != 1) + throw new InvalidCastException("Not a vector"); + Vector vec = new Vector(m.Rows); + vec.Add(m); + return vec; + } + + public static Vector operator +(Vector left, Matrix right) + { + return FromMatrix((Matrix)left + (Matrix)right); + } + public static Vector operator +(Matrix left, Vector right) + { + return FromMatrix((Matrix)left + (Matrix)right); + } + public static Vector operator +(Vector left, Vector right) + { + return FromMatrix((Matrix)left + (Matrix)right); + } + public static Vector operator -(Vector left, Vector right) + { + return FromMatrix((Matrix)left - (Matrix)right); + } + public static Vector operator -(Vector vec) + { + return FromMatrix(-(Matrix)vec); + } + + + + + /// + /// Реализация умножения вектора на матрицу + /// + public static Vector operator *(Matrix left, Vector right) + { + return FromMatrix((Matrix)left * (Matrix)right); + } + + public static Vector operator *(Vector left, double right) + { + Vector result = new Vector(left.Dimensions); + for (int i = 0; i < result.Dimensions; i++) + result[i] = left[i] * right; + return result; + } + + public static Vector operator /(Vector left, double right) + { + Vector result = new Vector(left.Dimensions); + for (int i = 0; i < result.Dimensions; i++) + result[i] = left[i] / right; + return result; + } + + + /// + /// Кмножение двух векторов через оператор будет возвращать их скалярное произведение + /// + public static double operator *(Vector left, Vector right) + { + return left.DotProduct(right); + } + + /// + /// Реализация скалярного произведения двух векторов + /// + public double DotProduct(Vector other) + { + double result = 0; + int length = Math.Min(Dimensions, other.Dimensions); + for (int i = 0; i < length; i++) + result += this[i] * other[i]; + return result; + } + + /// + /// Реализация скалярного произведения двух векторов + /// + public Vector CrossProduct(Vector other) + { + if (Dimensions != 3 || other.Dimensions != 3) + throw new InvalidOperationException("Can CrossProduct only 3D vectors"); + return new Vector(new double[] { + this[1]*other[2] - this[2]*other[1], + this[2]*other[0] - this[0]*other[2], + this[0]*other[1] - this[1]*other[0] + }); + } + + /// + /// Возвращает длину вектора + /// + public double Length + { + get + { + double len = 0; + for (int i = 0; i < Dimensions; i++) + len += Math.Pow(this[i], 2); + return Math.Sqrt(len); + } + } + + public Vector GetNormalized() + { + return this / Length; + } + } +} diff --git a/YMath/YMath.7z b/YMath/YMath.7z new file mode 100644 index 0000000000000000000000000000000000000000..727a3147b9b1a363a4cdf2e0b36e052f26ab0dab GIT binary patch literal 2944 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 literal 0 HcmV?d00001 diff --git a/YMath/YMath.csproj b/YMath/YMath.csproj new file mode 100644 index 0000000..8361ed2 --- /dev/null +++ b/YMath/YMath.csproj @@ -0,0 +1,10 @@ + + + + net5.0 + enable + nullable + + + +