2次元グリッド関数のレベルラインをプロットするための単純なクラス

科学活動に関連する主題分野のデータを処理する場合、多くの場合、2つの独立変数の機能を構築して視覚化する必要があります。 典型的な例は、いわゆるグリッド関数の形式で得られた2次元偏微分方程式を解いた結果を視覚的に提示する必要があることです。



関数のレベルライン(等値線)を構築するための単純なクラスが提案されます:Z = const(constは与えられた値のセット)を満たすXY平面上のラインの形式でZ = F(X、Y)。



関数Zは、四角形のセルを持つ任意のグリッド上の配列z [J、K]として定義されると想定されます。 グリッドは2つの配列x [J、K]、y [J、K]で定義されます。ここで、JとKはグリッドサイズです。



関数値は、四角形のセルの角で定義されます。 各セルで、計算されたレベル線がその面を通過するかどうかがチェックされ、線がセルを通過する場合、レベル線と面の交点の座標が計算されます。 セル内では、直線は直線で描画されます。



ソーステキストには詳細なコメントが記載されています。



LinesLevels.csファイル:



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); } } }
      
      





クラスの動作を実証するために、10 x 10グリッドでz = x ^ 2 + y ^ 2という形式の関数のレベル線を作成する小さなテストアプリケーションWPFが提案されています。



MainWindow.xamlファイル:



 <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>
      
      





そしてMainWindow.xaml.csコードファイル:



 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); } } }
      
      





テスト例の結果を図に示します:









ご清聴ありがとうございました!



All Articles