関数のレベルライン(等値線)を構築するための単純なクラスが提案されます: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); } } }
テスト例の結果を図に示します:
ご清聴ありがとうございました!