From 03db246d88f11b5ee20bd1f3f3497240603a40bf Mon Sep 17 00:00:00 2001 From: dm1sh Date: Fri, 4 Apr 2025 12:38:48 +0300 Subject: [PATCH] does not work --- Calculator.cs | 80 ++++++++++++++++ Configurator.cs | 96 +++++++++++++++++++ Drawer.cs | 67 +++++++++++++ MatrixOps.cs | 129 ++++++++++++++++++++++++++ Point.cs | 21 +++++ Program.cs | 17 ++++ omp.csproj | 17 ++++ test2.txt | 4 + test3.txt | 5 + Задание для домашней работы 2025.docx | Bin 0 -> 21065 bytes 10 files changed, 436 insertions(+) create mode 100644 Calculator.cs create mode 100644 Configurator.cs create mode 100644 Drawer.cs create mode 100644 MatrixOps.cs create mode 100644 Point.cs create mode 100644 Program.cs create mode 100644 omp.csproj create mode 100644 test2.txt create mode 100644 test3.txt create mode 100644 Задание для домашней работы 2025.docx diff --git a/Calculator.cs b/Calculator.cs new file mode 100644 index 0000000..a8e3560 --- /dev/null +++ b/Calculator.cs @@ -0,0 +1,80 @@ +namespace omp +{ + public class OverlappingPoints : Exception { } + + public static class Calculator + { + public const double StationPDOP = -1000; + + public static double[,] Jacobian1T(List stations, Point position) + { + int n = stations.Count; + double[,] J = new double[4, n]; + + for (int i = 0; i < n; ++i) + { + double distance = position.Distance(stations[i]); + + if (distance == 0) + { + throw new OverlappingPoints(); + } + + J[0, i] = -(stations[i].x - position.x) / distance; + J[1, i] = -(stations[i].y - position.y) / distance; + J[2, i] = -(stations[i].z - position.z) / distance; + J[3, i] = 1; // Clock bias + } + + return J; + } + + public static double PDOP(List stations, Point position) + { + double[,] JR = Jacobian1T(stations, position); + + double[,] mult = MatrixOps.MultTrans(JR); + + double det = MatrixOps.Det(mult); + + double sx2 = MatrixOps.Adj(mult, 0, 0) / det; + double sy2 = MatrixOps.Adj(mult, 1, 1) / det; + double sz2 = MatrixOps.Adj(mult, 2, 2) / det; + + return Math.Sqrt(sx2 + sy2 + sz2); + } + + public static void PDOPs(double[,] pdops, Configurator conf, out double min, out double max) + { + min = double.MaxValue; + max = double.MinValue; + + for (int i = 0; i < pdops.GetLength(0); ++i) + { + for (int j = 0; j < pdops.GetLength(1); ++j) + { + try + { + pdops[i, j] = PDOP(conf.stations, new Point(i, j, conf.zCoordinate)); + + if (pdops[i, j] > max) + { + max = pdops[i, j]; + } + + if (pdops[i, j] < min) + { + min = pdops[i, j]; + } + } + catch (OverlappingPoints) + { + pdops[i, j] = StationPDOP; + } + } + } + + Console.WriteLine("{0}...{1}", min, max); + } + } +} \ No newline at end of file diff --git a/Configurator.cs b/Configurator.cs new file mode 100644 index 0000000..fefeea0 --- /dev/null +++ b/Configurator.cs @@ -0,0 +1,96 @@ +namespace omp +{ + public class Configurator + { + public int xsize; + public int ysize; + public int zCoordinate; + public List stations = []; + + public Configurator(string[] args) + { + List lines; + + if (args.Length == 0) + { + Console.WriteLine("Input parameters:"); + + lines = []; + + string? line; + while ((line = Console.ReadLine()) != null && line != "") + { + lines.Add(line); + } + } + else if (args.Length == 1) + { + lines = new(File.ReadAllLines(args[0])); + } + else + { + throw new ArgumentException("You must either provide path to parameters file as an only cli argument, or insert it into STDIN"); + } + + ParseParameters(lines); + } + + private void ParseParameters(IReadOnlyList lines) + { + bool hasZ = CheckHasZ(lines[1]); + + ParseSize(lines[0]); + ParseZCoord(lines[1], hasZ); + ParseStations(lines, hasZ); + } + + private static bool CheckHasZ(string line) + { + return line.Split(' ').Length == 1; // line contains a single number, z coordinate + } + + private void ParseSize(string line) + { + string[] size_parts = line.Split(' ', 2); + xsize = int.Parse(size_parts[0]); + ysize = int.Parse(size_parts[1]); + } + + private void ParseZCoord(string line, bool hasZ) + { + if (hasZ) + { + zCoordinate = int.Parse(line); + } + else + { + zCoordinate = 0; + } + } + + private void ParseStations(IReadOnlyList lines, bool hasZ) + { + int firstIndex = 1 + (hasZ ? 1 : 0); + for (int i = firstIndex; i < lines.Count; ++i) + { + string[] point_parts = lines[i].Split(' ', 2 + (hasZ ? 1 : 0)); + + int x, y, z; + + x = int.Parse(point_parts[0]) - 1; + y = int.Parse(point_parts[1]) - 1; + + if (hasZ) + { + z = int.Parse(point_parts[2]); + } + else + { + z = 0; + } + + stations.Add(new Point(x, y, z)); + } + } + } +} \ No newline at end of file diff --git a/Drawer.cs b/Drawer.cs new file mode 100644 index 0000000..c45d8ed --- /dev/null +++ b/Drawer.cs @@ -0,0 +1,67 @@ +using SkiaSharp; + +namespace omp +{ + class Drawer + { + public static void Draw(Configurator conf, double[,] pdops, double min, double max) + { + var bitmap = new SKBitmap(conf.xsize, conf.ysize); + + for (int i = 0; i < conf.xsize; ++i) + { + for (int j = 0; j < conf.ysize; ++j) + { + SKColor color; + + if (pdops[i, j] == Calculator.StationPDOP) + { + color = SKColors.White; + } + else + { + double t = (pdops[i, j] - min) / (max - min); + color = Map2Color(t); + } + + bitmap.SetPixel(i, j, color); + } + } + + using (var image = SKImage.FromBitmap(bitmap)) + using (var data = image.Encode(SKEncodedImageFormat.Png, 100)) + using (var stream = File.OpenWrite("out.png")) + { + data.SaveTo(stream); + } + } + + public static SKColor Map2Color(double t) + { + if (t < 0.25) + { + // Blue to cyan + double localT = t / 0.25; + return new SKColor(0, (byte)(255 * localT), 255); + } + else if (t < 0.5) + { + // Cyan to green + double localT = (t - 0.25) / 0.25; + return new SKColor(0, 255, (byte)(255 * (1 - localT))); + } + else if (t < 0.75) + { + // Green to yellow + double localT = (t - 0.5) / 0.25; + return new SKColor((byte)(255 * localT), 255, 0); + } + else + { + // Yellow to red + double localT = (t - 0.75) / 0.25; + return new SKColor(255, (byte)(255 * (1 - localT)), 0); + } + } + } +} \ No newline at end of file diff --git a/MatrixOps.cs b/MatrixOps.cs new file mode 100644 index 0000000..338e381 --- /dev/null +++ b/MatrixOps.cs @@ -0,0 +1,129 @@ +namespace omp +{ + public static class MatrixOps + { + public static void Print(double[,] a) + { + int rows = a.GetLength(0); + int columns = a.GetLength(1); + + Console.WriteLine("Matrix of size {0}x{1}:", rows, columns); + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < columns; j++) + { + Console.Write("\t{0}", a[i, j]); + } + Console.WriteLine(""); + } + } + + public static double Adj(double[,] a, int i, int j) + { + double sgn = ((i + j) % 2 == 0) ? 1 : -1; + + return sgn * Det(Minor(a, j, i)); + } + + public static double[,] Minor(double[,] a, int i, int j) + { + int rows = a.GetLength(0); + int columns = a.GetLength(1); + + double[,] minor = new double[rows - 1, columns - 1]; + + int k = 0; + int l; + + for (int r = 0; r < rows; ++r) + { + if (r == i) + { + continue; + } + + l = 0; + + for (int c = 0; c < columns; ++c) + { + if (c == j) + { + continue; + } + + minor[k, l] = a[r, c]; + + l++; + } + + k++; + } + + return minor; + } + + public static double Det(double[,] a) + { + int n = a.GetLength(0); + + switch (n) + { + case 2: + return Det2(a); + case 3: + return Det3(a); + default: + double det = 0; + + double sgn; + for (int j = 0; j < n; ++j) + { + sgn = (j % 2 == 0) ? 1 : -1; + det += sgn * a[0, j] * Det(Minor(a, 0, j)); + } + + return det; + } + } + + public static double Det2(double[,] a) + { + return a[0, 0] * a[1, 1] - a[0, 1] * a[1, 0]; + } + + public static double Det3(double[,] a) + { + if (a.GetLength(0) != 3 || a.GetLength(1) != 3) + throw new ArgumentException("Matrix must be 3x3"); + + return + a[0, 0] * a[1, 1] * a[2, 2] + + a[0, 1] * a[1, 2] * a[2, 0] + + a[0, 2] * a[1, 0] * a[2, 1] + - a[0, 2] * a[1, 1] * a[2, 0] + - a[0, 0] * a[1, 2] * a[2, 1] + - a[2, 2] * a[0, 1] * a[1, 0]; + } + + public static double[,] MultTrans(double[,] a) + { + int rows = a.GetLength(0); + int columns = a.GetLength(1); + + double[,] r = new double[rows, rows]; + + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < rows; j++) + { + for (int k = 0; k < columns; k++) + { + r[i, j] += a[i, k] * a[j, k]; + } + } + } + + return r; + } + } +} \ No newline at end of file diff --git a/Point.cs b/Point.cs new file mode 100644 index 0000000..673ce69 --- /dev/null +++ b/Point.cs @@ -0,0 +1,21 @@ +namespace omp +{ + public class Point(int x, int y, int z) + { + public int x = x, y = y, z = z; + + public double Distance(Point a) + { + double dx = x - a.x; + double dy = y - a.y; + double dz = z - a.z; + + return Math.Sqrt(dx * dx + dy * dy + dz * dz); + } + + public bool Equals(Point a) + { + return (x == a.x) && (y == a.y) && (z == a.z); + } + } +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..e91fc30 --- /dev/null +++ b/Program.cs @@ -0,0 +1,17 @@ +namespace omp +{ + public class DOPCalculator + { + public static void Main(string[] args) + { + Configurator conf = new(args); + + double[,] pdops = new double[conf.xsize, conf.ysize]; + double min, max; + + Calculator.PDOPs(pdops, conf, out min, out max); + + Drawer.Draw(conf, pdops, min, max); + } + } +} diff --git a/omp.csproj b/omp.csproj new file mode 100644 index 0000000..35edc10 --- /dev/null +++ b/omp.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + + + diff --git a/test2.txt b/test2.txt new file mode 100644 index 0000000..d2d31a6 --- /dev/null +++ b/test2.txt @@ -0,0 +1,4 @@ +500 500 +1 +100 499 0 +400 499 0 \ No newline at end of file diff --git a/test3.txt b/test3.txt new file mode 100644 index 0000000..cc9e64c --- /dev/null +++ b/test3.txt @@ -0,0 +1,5 @@ +1000 1000 +0 +236 134 0 +147 863 0 +915 591 0 \ No newline at end of file diff --git a/Задание для домашней работы 2025.docx b/Задание для домашней работы 2025.docx new file mode 100644 index 0000000000000000000000000000000000000000..f39ae13318a9a7a0ed1223041a3224165f6d2357 GIT binary patch literal 21065 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 literal 0 HcmV?d00001