📜 ⬆️ ⬇️

A simple class for building lines of the level of a two-dimensional grid function

When processing data in subject areas related to scientific activity, it is often necessary to construct and visualize the function of two independent variables. A typical example is the need for a visual representation of the results of solving two-dimensional partial differential equations, obtained in the form of so-called grid functions.

A simple class is proposed for plotting the level lines (isolines) of the function: Z = F (X, Y) in the form of lines on the XY plane, satisfying the equations Z = const (where const is a set of given values).

It is assumed that the function Z is specified as an array z [J, K] on an arbitrary grid with quadrilateral cells. The grid is defined by two arrays x [J, K], y [J, K], where J and K are the dimensions of the grid.

The values ​​of the function are defined in the corners of the quadrilateral cell. In each cell, the passage of the calculated level line through its faces is checked and, provided that the line passes through the cell, the coordinates of the intersection of the level line with the faces are calculated. Inside the cell, the line is drawn in a straight line.
')
The source text is provided with detailed comments.

LinesLevels.cs file:

using System.Collections.Generic; using System.Linq; using System.Windows; namespace WpfLinesLevels { public class LinesOfLevels { private int J, K; private double[,] X; private double[,] Y; private double[,] Z; //   public List<LineLevel> Lines { get; set; } /// <summary> ///  /// </summary> /// <param name="_levels"> </param> /// <param name="_x"> X </param> /// <param name="_y"> Y </param> /// <param name="_z"> </param> public LinesOfLevels(double[] _levels, double[,] _x, double[,] _y, double[,] _z) { Lines = new List<LineLevel>(_levels.Count()); foreach (double l in _levels) { Lines.Add(new LineLevel(l)); } X = _x; Y = _y; Z = _z; J = X.GetLength(0); K = X.GetLength(1); } /// <summary> ///  . /// </summary> public void Calculate() { for (int j = 0; j < J - 1; j++) for (int k = 0; k < K - 1; k++) { Ceil ir = new Ceil(j, k, X, Y, Z); for (int l = 0; l < Lines.Count(); l++) ir.AddIntoLineLevel(Lines[l]); } } } /// <summary> ///   /// </summary> public class LineLevel { //        //     public List<PairOfPoints> Pairs { get; set; } //   public double Level { get; set; } public LineLevel(double _level) { Level = _level; Pairs = new List<PairOfPoints>(); } } /// <summary> ///   ,    /// </summary> public class PairOfPoints { public List<Point> Points { get; set; } public PairOfPoints() { Points = new List<Point>(); } } /// <summary> ///  . ///        /// </summary> internal struct Dot { internal int j { get; set; } internal int k { get; set; } internal Dot(int _j, int _k) { j = _j; k = _k; } } /// <summary> ///   .   . ///      /// </summary> internal class Ceil { //   private Dot[] d = new Dot[4]; //    private Point[] r = new Point[4]; //     private double[,] X; private double[,] Y; //    private double[,] Z; /// <summary> ///   ///    .       1   J,K  /// </summary> /// <param name="_j">j -    </param> /// <param name="_k">k -    </param> /// <param name="_x"> X[J,K]</param> /// <param name="_y"> Y[J,K]</param> /// <param name="_z">   Z[J,K]</param> internal Ceil(int _j, int _k, double[,] _x, double[,] _y, double[,] _z) { d[0] = new Dot(_j, _k); d[1] = new Dot(_j + 1, _k); d[2] = new Dot(_j + 1, _k + 1); d[3] = new Dot(_j, _k + 1); X = _x; Y = _y; Z = _z; r[0] = dotPoint(d[0]); r[1] = dotPoint(d[1]); r[2] = dotPoint(d[2]); r[3] = dotPoint(d[3]); } /// <summary> ///    Point  /// </summary> /// <param name="_d">,   Dot</param> /// <returns></returns> private Point dotPoint(Dot _d) { return new Point(X[_d.j, _d.k], Y[_d.j, _d.k]); } /// <summary> ///      /// </summary> /// <param name="_d">,   Dot</param> /// <returns></returns> private double dotZ(Dot _d) { return Z[_d.j, _d.k]; } /// <summary> ///   ,      ///       . /// </summary> /// <param name="_l">  </param> /// <returns></returns> private PairOfPoints ByLevel(double _l) { PairOfPoints p = new PairOfPoints(); //  0 if ((dotZ(d[0]) >= _l && dotZ(d[1]) < _l) || (dotZ(d[1]) > _l && dotZ(d[0]) <= _l)) { double t = (_l - dotZ(d[1])) / (dotZ(d[0]) - dotZ(d[1])); double x = r[0].X * t + r[1].X * (1 - t); double y = r[0].Y * t + r[1].Y * (1 - t); p.Points.Add(new Point(x, y)); } //  1 if ((dotZ(d[1]) >= _l && dotZ(d[2]) < _l) || (dotZ(d[2]) > _l && dotZ(d[1]) <= _l)) { double t = (_l - dotZ(d[2])) / (dotZ(d[1]) - dotZ(d[2])); double x = r[1].X * t + r[2].X * (1 - t); double y = r[1].Y * t + r[2].Y * (1 - t); p.Points.Add(new Point(x, y)); if (p.Points.Count == 2) return p; } //  2 if ((dotZ(d[2]) >= _l && dotZ(d[3]) < _l) || (dotZ(d[3]) > _l && dotZ(d[2]) <= _l)) { double t = (_l - dotZ(d[3])) / (dotZ(d[2]) - dotZ(d[3])); double x = r[2].X * t + r[3].X * (1 - t); double y = r[2].Y * t + r[3].Y * (1 - t); p.Points.Add(new Point(x, y)); if (p.Points.Count == 2) return p; } //  3 if ((dotZ(d[3]) >= _l && dotZ(d[0]) < _l) || (dotZ(d[0]) > _l && dotZ(d[3]) <= _l)) { double t = (_l - dotZ(d[0])) / (dotZ(d[3]) - dotZ(d[0])); double x = r[3].X * t + r[0].X * (1 - t); double y = r[3].Y * t + r[0].Y * (1 - t); p.Points.Add(new Point(x, y)); } return p; } /// <summary> ///       /// </summary> /// <param name="_lL"> </param> internal void AddIntoLineLevel(LineLevel _lL) { PairOfPoints lp = ByLevel(_lL.Level); if (lp.Points.Count > 0) _lL.Pairs.Add(lp); } } } 

To demonstrate the work of the class, a small WPF test application is proposed, which builds level lines for a function of the form: z = x ^ 2 + y ^ 2 on a 10 by 10 grid.

MainWindow.xaml file:

 <Window x:Class="WpfLinesLevels.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfLinesLevels" mc:Ignorable="d" Title=" Z = X^2+Y^2" Height="590" Width="525"> <Grid Name="grid1"> </Grid> </Window> 

And the MainWindow.xaml.cs code file:

 using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; namespace WpfLinesLevels { /// <summary> ///    MainWindow.xaml /// </summary> public partial class MainWindow : Window { private double Xmax; private double Xmin; private double Ymax; private double Ymin; private double xSt; private double ySt; public MainWindow() { InitializeComponent(); //  ,    double[] levels = { 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; double[,] X = new double[10, 10]; double[,] Y = new double[10, 10]; double[,] Z = new double[10, 10]; //        Xmax = 10; Xmin = 0; Ymax = 10; Ymin = 0; xSt = 525 / (Xmax - Xmin); ySt = 525 / (Ymax - Ymin); //      for (int k = 0; k < 10; k++) for (int j = 0; j < 10; j++) { X[j, k] = j; Y[j, k] = k; Z[j, k] = j * j + k * k; } //   LinesOfLevels lol = new LinesOfLevels(levels, X, Y, Z); //   lol.Calculate(); //  DrowLevelLine(lol, X, Y); } /// <summary> ///    /// </summary> /// <param name="lL">   </param> /// <param name="x"> X </param> /// <param name="y"> Y </param> private void DrowLevelLine(LinesOfLevels lL, double[,] x, double[,] y) { Canvas can = new Canvas(); foreach (LineLevel l in lL.Lines) { foreach (PairOfPoints pp in l.Pairs) { if (pp.Points.Count() == 2) { Line pl = new Line(); pl.Stroke = new SolidColorBrush(Colors.BlueViolet); pl.X1 = xCalc(pp.Points[0].X); pl.X2 = xCalc(pp.Points[1].X); pl.Y1 = yCalc(pp.Points[0].Y); pl.Y2 = yCalc(pp.Points[1].Y); can.Children.Add(pl); } } } can.Margin = new Thickness(10, 10, 10, 10); can.VerticalAlignment = VerticalAlignment.Stretch; can.HorizontalAlignment = HorizontalAlignment.Stretch; grid1.Children.Add(can); } /// <summary> ///    X   /// </summary> /// <param name="_x">  X</param> /// <returns>  X</returns> private double xCalc(double _x) { return xSt * (_x - Xmin); } /// <summary> ///    Y   /// </summary> /// <param name="_x">  Y</param> /// <returns>  Y</returns> private double yCalc(double _y) { return ySt * (Ymax - _y); } } } 

The result of the test case is shown in the figure:


Thanks for attention!

Source: https://habr.com/ru/post/313116/


All Articles