diff --git a/Crystallography.Controls/Crystal/AtomCoordinateTable.cs b/Crystallography.Controls/Crystal/AtomCoordinateTable.cs index a2fb4a1..bf53fa5 100644 --- a/Crystallography.Controls/Crystal/AtomCoordinateTable.cs +++ b/Crystallography.Controls/Crystal/AtomCoordinateTable.cs @@ -6,310 +6,308 @@ using System.Threading.Tasks; using System.Windows.Forms; -namespace Crystallography.Controls +namespace Crystallography.Controls; + +public partial class AtomCoordinateTable : UserControl { - public partial class AtomCoordinateTable : UserControl + readonly ReaderWriterLockSlim rwLock = new(); + private bool skipEvent { get; set; } = false; + public AtomCoordinateTable() { - readonly ReaderWriterLockSlim rwLock = new(); - private bool skipEvent { get; set; } = false; - public AtomCoordinateTable() - { - InitializeComponent(); - } + InitializeComponent(); + } - private Crystal crystal; + private Crystal crystal; - public Crystal Crystal + public Crystal Crystal + { + set { - set + crystal = value; + if (crystal != null && crystal.Atoms != null && crystal.Atoms.Length > 0) { - crystal = value; - if (crystal != null && crystal.Atoms != null && crystal.Atoms.Length > 0) - { - skipEvent = true; - comboBox.Items.Clear(); - for (int i = 0; i < crystal.Atoms.Length; i++) - comboBox.Items.Add(crystal.Atoms[i].Label); - skipEvent = false; - comboBox.SelectedIndex = 0; - } + skipEvent = true; + comboBox.Items.Clear(); + for (int i = 0; i < crystal.Atoms.Length; i++) + comboBox.Items.Add(crystal.Atoms[i].Label); + skipEvent = false; + comboBox.SelectedIndex = 0; } - get { return crystal; } } + get => crystal; + } - private Atoms atom; + private Atoms atom; - public Atoms Atom + public Atoms Atom + { + set { - set + atom = value; + if (atom != null) { - atom = value; - if (atom != null) - { - for (int i = 0; i < crystal.Atoms.Length; i++) - if (crystal.Atoms[i] == atom) - { - comboBox.SelectedIndex = i; - break; - } - } + for (int i = 0; i < crystal.Atoms.Length; i++) + if (crystal.Atoms[i] == atom) + { + comboBox.SelectedIndex = i; + break; + } } - get => atom; } + get => atom; + } - private void comboBox_SelectedIndexChanged(object sender, EventArgs e) + private void comboBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (skipEvent) + return; + if (crystal != null && crystal.Atoms != null && crystal.Atoms.Length > 0 && comboBox.SelectedIndex < Crystal.Atoms.Length) { - if (skipEvent) - return; - if (crystal != null && crystal.Atoms != null && crystal.Atoms.Length > 0 && comboBox.SelectedIndex < Crystal.Atoms.Length) - { - atom = Crystal.Atoms[comboBox.SelectedIndex]; - RefreshTable(); - } + atom = Crystal.Atoms[comboBox.SelectedIndex]; + RefreshTable(); } + } - private void RefreshTable() + private void RefreshTable() + { + if (crystal != null && crystal.Atoms != null && crystal.Atoms.Length > 0 && comboBox.SelectedIndex < Crystal.Atoms.Length) { - if (crystal != null && crystal.Atoms != null && crystal.Atoms.Length > 0 && comboBox.SelectedIndex < Crystal.Atoms.Length) + var atom = Search(Crystal, Atom, (double)numericUpDownMaxLength.Value); + dataSet.Tables[0].Clear(); + for (int i = 0; i < atom.Count; i++) { - var atom = Search(Crystal, Atom, (double)numericUpDownMaxLength.Value); - dataSet.Tables[0].Clear(); - for (int i = 0; i < atom.Count; i++) - { - dataSet.Tables[0].Rows.Add(new object[] { - atom[i].Label, - atom[i].Distance - }); - } - DrawGraph(atom); + dataSet.Tables[0].Rows.Add(new object[] { + atom[i].Label, + atom[i].Distance + }); } + DrawGraph(atom); } + } - public List<(string Label, double Distance)> Search(Crystal crystal, Atoms targetAtom, double maxLengthAngstrom) + public List<(string Label, double Distance)> Search(Crystal crystal, Atoms targetAtom, double maxLengthAngstrom) + { + var mat = 10 * crystal.MatrixReal; + Vector3DBase pos = mat * targetAtom.Atom[0]; + var max2 = maxLengthAngstrom * maxLengthAngstrom; + var atoms = new List<(string Label, double Distance)>(); + //まず、隣り合った単位格子の原子位置をすべて探索してCoordinatedAtom型のリストに全部入れる + for (int max = 0; max < 8; max++) { - var mat = 10 * crystal.MatrixReal; - Vector3DBase pos = mat * targetAtom.Atom[0]; - var max2 = maxLengthAngstrom * maxLengthAngstrom; - var atoms = new List<(string Label, double Distance)>(); - //まず、隣り合った単位格子の原子位置をすべて探索してCoordinatedAtom型のリストに全部入れる - for (int max = 0; max < 8; max++) + bool flag = false; + Parallel.For(-max, max + 1, xShift => { - bool flag = false; - Parallel.For(-max, max + 1, xShift => - { - for (int yShift = -max; yShift <= max; yShift++) - for (int zShift = -max; zShift <= max; zShift++) + for (int yShift = -max; yShift <= max; yShift++) + for (int zShift = -max; zShift <= max; zShift++) + { + if (Math.Abs(xShift) == max || Math.Abs(yShift) == max || Math.Abs(zShift) == max) { - if (Math.Abs(xShift) == max || Math.Abs(yShift) == max || Math.Abs(zShift) == max) - { - foreach (Atoms atm in crystal.Atoms) - foreach (var v in atm.Atom) + foreach (var atm in crystal.Atoms) + foreach (var v in atm.Atom) + { + var tempPos = mat * (v + new Vector3DBase(xShift, yShift, zShift)); + if (max2 > (tempPos - pos).Length2) { - var tempPos = mat * (v + new Vector3DBase(xShift, yShift, zShift)); - if (max2 > (tempPos - pos).Length2) + rwLock.EnterWriteLock(); + try { - rwLock.EnterWriteLock(); - try - { - atoms.Add((atm.Label, (tempPos - pos).Length)); - flag = true;//一個でも見つけられたら続行 - } - finally { rwLock.ExitWriteLock(); } + atoms.Add((atm.Label, (tempPos - pos).Length)); + flag = true;//一個でも見つけられたら続行 } + finally { rwLock.ExitWriteLock(); } } - } + } } - }); - if (flag == false && max > 2) - break; - } - atoms.Sort((a1, a2) => a1.Distance.CompareTo(a2.Distance)); - return atoms; + } + }); + if (flag == false && max > 2) + break; } + atoms.Sort((a1, a2) => a1.Distance.CompareTo(a2.Distance)); + return atoms; + } - private Bitmap bmp; - private Graphics g; - private Point OriginPos = new(30, 30); - private double UpperX, LowerX, UpperY, LowerY; - private readonly Profile profile = new(); - private double BottomMargin = 0; + private Bitmap bmp; + private Graphics g; + private Point OriginPos = new(30, 30); + private double UpperX, LowerX, UpperY, LowerY; + private readonly Profile profile = new(); + private double BottomMargin = 0; - private void DrawGraph(List<(string Label, double Distance)> atoms) + private void DrawGraph(List<(string Label, double Distance)> atoms) + { + if (pictureBox.Width <= 0 || pictureBox.Height <= 0 || atoms.Count == 0) return; bmp = new Bitmap(pictureBox.Width, pictureBox.Height); + g = Graphics.FromImage(bmp); + g.Clear(Color.White); + g.SmoothingMode = SmoothingMode.AntiAlias; + this.DoubleBuffered = true; + + //上限、下限を決める + double width = (double)numericUpDownWidth.Value; + LowerX = 0; + UpperX = atoms[^1].Distance + width * 2; + LowerY = 0; + + List controlPoint = []; + //すべてのCoordinatedAtomにたいする始点をPositiveに、終点をNegativeに格納する + for (int i = 0; i < atoms.Count; i++) { - if (pictureBox.Width <= 0 || pictureBox.Height <= 0 || atoms.Count == 0) return; bmp = new Bitmap(pictureBox.Width, pictureBox.Height); - g = Graphics.FromImage(bmp); - g.Clear(Color.White); - g.SmoothingMode = SmoothingMode.AntiAlias; - this.DoubleBuffered = true; - - //上限、下限を決める - double width = (double)numericUpDownWidth.Value; - LowerX = 0; - UpperX = atoms[^1].Distance + width * 2; - LowerY = 0; - - List controlPoint = []; - //すべてのCoordinatedAtomにたいする始点をPositiveに、終点をNegativeに格納する - for (int i = 0; i < atoms.Count; i++) - { - controlPoint.Add(new ControlPoint(atoms[i].Distance - width, true)); - controlPoint.Add(new ControlPoint(atoms[i].Distance + width, false)); - } - controlPoint.Sort(); + controlPoint.Add(new ControlPoint(atoms[i].Distance - width, true)); + controlPoint.Add(new ControlPoint(atoms[i].Distance + width, false)); + } + controlPoint.Sort(); - double height = 0; - UpperY = 2; - profile.Clear(); - profile.Pt.Add(new PointD(-width * 2, 0)); - for (int i = 0; i < controlPoint.Count; i++) - { - profile.Pt.Add(new PointD(controlPoint[i].X, height)); - if (controlPoint[i].Flag) - height++; - else - height--; - profile.Pt.Add(new PointD(controlPoint[i].X, height)); - - if (UpperY < height) - UpperY = height; - } - profile.Pt.Add(new PointD(UpperX, 0)); - UpperY += 2; + double height = 0; + UpperY = 2; + profile.Clear(); + profile.Pt.Add(new PointD(-width * 2, 0)); + for (int i = 0; i < controlPoint.Count; i++) + { + profile.Pt.Add(new PointD(controlPoint[i].X, height)); + if (controlPoint[i].Flag) + height++; + else + height--; + profile.Pt.Add(new PointD(controlPoint[i].X, height)); + + if (UpperY < height) + UpperY = height; + } + profile.Pt.Add(new PointD(UpperX, 0)); + UpperY += 2; - DrawHistogram(atoms); - DrawGraduation(); - DrawLabel(atoms); + DrawHistogram(atoms); + DrawGraduation(); + DrawLabel(atoms); - pictureBox.Image = bmp; - } + pictureBox.Image = bmp; + } - private class ControlPoint(double x, bool flag) : IComparable - { - public double X = x; - public bool Flag = flag; + private class ControlPoint(double x, bool flag) : IComparable + { + public double X = x; + public bool Flag = flag; - public int CompareTo(object obj) - { - return X.CompareTo(((ControlPoint)obj).X); - } + public int CompareTo(object obj) + { + return X.CompareTo(((ControlPoint)obj).X); } + } - private void DrawHistogram(List<(string Label, double Distance)> atoms) + private void DrawHistogram(List<(string Label, double Distance)> atoms) + { + var solidBrush = new SolidBrush(Color.LawnGreen); + var zero = ConvToPicBoxCoord(0, 0).Y; + for (int i = 0; i < profile.Pt.Count - 1; i++) { - var solidBrush = new SolidBrush(Color.LawnGreen); - var zero = ConvToPicBoxCoord(0, 0).Y; - for (int i = 0; i < profile.Pt.Count - 1; i++) - { - var p1 = ConvToPicBoxCoord(profile.Pt[i]); - var p2 = ConvToPicBoxCoord(profile.Pt[i + 1]); - if (Math.Abs(p1.X - p2.X) > 0.2) - g.FillRectangle(solidBrush, new RectangleF(p1.X, p1.Y, p2.X - p1.X, zero - p1.Y)); - } + var p1 = ConvToPicBoxCoord(profile.Pt[i]); + var p2 = ConvToPicBoxCoord(profile.Pt[i + 1]); + if (Math.Abs(p1.X - p2.X) > 0.2) + g.FillRectangle(solidBrush, new RectangleF(p1.X, p1.Y, p2.X - p1.X, zero - p1.Y)); } + } - private void DrawLabel(List<(string Label, double Distance)> atoms) + private void DrawLabel(List<(string Label, double Distance)> atoms) + { + var JustBeforePt = new PointF(-10, -10); + var JustBeforeLabel = ""; + int times = 1; + int shiftY = 15; + Font font = new Font("Tahoma", 9); + Brush br = new SolidBrush(Color.Red); + for (int i = 0; i < atoms.Count; i++) { - var JustBeforePt = new PointF(-10, -10); - var JustBeforeLabel = ""; - int times = 1; - int shiftY = 15; - Font font = new Font("Tahoma", 9); - Brush br = new SolidBrush(Color.Red); - for (int i = 0; i < atoms.Count; i++) + while (i < atoms.Count - 1 && Math.Abs(atoms[i].Distance - atoms[i + 1].Distance) < 0.00000000001 && atoms[i].Label == atoms[i + 1].Label)//次も同じ元素が来る場合は { - while (i < atoms.Count - 1 && Math.Abs(atoms[i].Distance - atoms[i + 1].Distance) < 0.00000000001 && atoms[i].Label == atoms[i + 1].Label)//次も同じ元素が来る場合は - { - times++; - i++; - } - PointF pt = ConvToPicBoxCoord(atoms[i].Distance, 0); - - if (pt.X - JustBeforePt.X < 40 && JustBeforePt.Y - shiftY > 0)//字がかぶらないようにするための措置 - pt.Y = JustBeforePt.Y - shiftY; - else - pt.Y -= shiftY * 2; - - JustBeforePt = pt; - JustBeforeLabel = atoms[i].Label; - if (times == 1) - g.DrawString(atoms[i].Label.TrimEnd(new char[] { ' ' }), font, br, pt); - else - g.DrawString(atoms[i].Label.TrimEnd(new char[] { ' ' }) + "(" + times.ToString() + ")", font, br, pt); - times = 1; + times++; + i++; } + PointF pt = ConvToPicBoxCoord(atoms[i].Distance, 0); + + if (pt.X - JustBeforePt.X < 40 && JustBeforePt.Y - shiftY > 0)//字がかぶらないようにするための措置 + pt.Y = JustBeforePt.Y - shiftY; + else + pt.Y -= shiftY * 2; + + JustBeforePt = pt; + JustBeforeLabel = atoms[i].Label; + if (times == 1) + g.DrawString(atoms[i].Label.TrimEnd(new char[] { ' ' }), font, br, pt); + else + g.DrawString(atoms[i].Label.TrimEnd(new char[] { ' ' }) + "(" + times.ToString() + ")", font, br, pt); + times = 1; } - - private void DrawGraduation() + } + private void DrawGraduation() + { + g.FillRectangle(new SolidBrush(Color.White), 0, 0, OriginPos.X, pictureBox.Height); + g.FillRectangle(new SolidBrush(Color.White), 0, pictureBox.Height - OriginPos.Y, pictureBox.Width, pictureBox.Height); + + float AngleGradiation;//ここより角度目盛りの描画 + double d = (UpperX - LowerX) / Math.Pow(10, (int)Math.Log10(UpperX - LowerX)); + if (d < 1.1) AngleGradiation = (float)(Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); + else if (d < 2.2) AngleGradiation = (float)(2 * Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); + else if (d < 5.0) AngleGradiation = (float)(5 * Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); + else AngleGradiation = (float)(10 * Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); + g.DrawLine(new Pen(Color.Black, 1), OriginPos.X, pictureBox.Height - OriginPos.Y, pictureBox.Width, pictureBox.Height - OriginPos.Y); + Font strFont = new(new FontFamily("tahoma"), 8); + for (int i = (int)(LowerX / AngleGradiation) + 1; i < UpperX / AngleGradiation; i++) { - g.FillRectangle(new SolidBrush(Color.White), 0, 0, OriginPos.X, pictureBox.Height); - g.FillRectangle(new SolidBrush(Color.White), 0, pictureBox.Height - OriginPos.Y, pictureBox.Width, pictureBox.Height); - - float AngleGradiation;//ここより角度目盛りの描画 - double d = (UpperX - LowerX) / Math.Pow(10, (int)Math.Log10(UpperX - LowerX)); - if (d < 1.1) AngleGradiation = (float)(Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); - else if (d < 2.2) AngleGradiation = (float)(2 * Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); - else if (d < 5.0) AngleGradiation = (float)(5 * Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); - else AngleGradiation = (float)(10 * Math.Pow(10, (int)Math.Log10(UpperX - LowerX) - 1)); - g.DrawLine(new Pen(Color.Black, 1), OriginPos.X, pictureBox.Height - OriginPos.Y, pictureBox.Width, pictureBox.Height - OriginPos.Y); - Font strFont = new(new FontFamily("tahoma"), 8); - for (int i = (int)(LowerX / AngleGradiation) + 1; i < UpperX / AngleGradiation; i++) - { - g.DrawLine(new Pen(Color.Black, 1), ConvToPicBoxCoord(i * AngleGradiation, 0).X, pictureBox.Height - OriginPos.Y, ConvToPicBoxCoord(i * AngleGradiation, 0).X, pictureBox.Height - OriginPos.Y + 5); - g.DrawString(Math.Round(i * AngleGradiation, 5).ToString("#,#.###############"), strFont, new SolidBrush(Color.Black), ConvToPicBoxCoord(i * AngleGradiation, 0).X - 2, pictureBox.Height - OriginPos.Y + 5); - g.DrawLine(new Pen(Color.LightGray, 1), ConvToPicBoxCoord(i * AngleGradiation, 0).X, pictureBox.Height - OriginPos.Y, ConvToPicBoxCoord(i * AngleGradiation, 0).X, 0); - } + g.DrawLine(new Pen(Color.Black, 1), ConvToPicBoxCoord(i * AngleGradiation, 0).X, pictureBox.Height - OriginPos.Y, ConvToPicBoxCoord(i * AngleGradiation, 0).X, pictureBox.Height - OriginPos.Y + 5); + g.DrawString(Math.Round(i * AngleGradiation, 5).ToString("#,#.###############"), strFont, new SolidBrush(Color.Black), ConvToPicBoxCoord(i * AngleGradiation, 0).X - 2, pictureBox.Height - OriginPos.Y + 5); + g.DrawLine(new Pen(Color.LightGray, 1), ConvToPicBoxCoord(i * AngleGradiation, 0).X, pictureBox.Height - OriginPos.Y, ConvToPicBoxCoord(i * AngleGradiation, 0).X, 0); + } - float IntensityGradiation;//ここより強度目盛りの描画 - d = (UpperY - LowerY) / Math.Pow(10, (int)Math.Log10(UpperY - LowerY)); - if (d < 1.6) IntensityGradiation = (float)(Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); - else if (d < 2.2) IntensityGradiation = (float)(2 * Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); - else if (d < 8.0) IntensityGradiation = (float)(5 * Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); - else IntensityGradiation = (float)(10 * Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); - g.DrawLine(new Pen(Color.Black, 1), OriginPos.X, 0, OriginPos.X, pictureBox.Height - OriginPos.Y); - for (int i = (int)(LowerY / IntensityGradiation) + 1; i < UpperY / IntensityGradiation; i++) - { - g.DrawLine(new Pen(Color.Black, 1), OriginPos.X - 8, ConvToPicBoxCoord(0, i * IntensityGradiation).Y, OriginPos.X, ConvToPicBoxCoord(0, i * IntensityGradiation).Y); - g.DrawString((i * IntensityGradiation).ToString("#,#.###############"), strFont, new SolidBrush(Color.Black), 0, ConvToPicBoxCoord(0, i * IntensityGradiation).Y - 6); - g.DrawLine(new Pen(Color.LightGray, 1), OriginPos.X - 8, ConvToPicBoxCoord(0, i * IntensityGradiation).Y, pictureBox.Width, ConvToPicBoxCoord(0, i * IntensityGradiation).Y); - } + float IntensityGradiation;//ここより強度目盛りの描画 + d = (UpperY - LowerY) / Math.Pow(10, (int)Math.Log10(UpperY - LowerY)); + if (d < 1.6) IntensityGradiation = (float)(Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); + else if (d < 2.2) IntensityGradiation = (float)(2 * Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); + else if (d < 8.0) IntensityGradiation = (float)(5 * Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); + else IntensityGradiation = (float)(10 * Math.Pow(10, (int)Math.Log10(UpperY - LowerY) - 1)); + g.DrawLine(new Pen(Color.Black, 1), OriginPos.X, 0, OriginPos.X, pictureBox.Height - OriginPos.Y); + for (int i = (int)(LowerY / IntensityGradiation) + 1; i < UpperY / IntensityGradiation; i++) + { + g.DrawLine(new Pen(Color.Black, 1), OriginPos.X - 8, ConvToPicBoxCoord(0, i * IntensityGradiation).Y, OriginPos.X, ConvToPicBoxCoord(0, i * IntensityGradiation).Y); + g.DrawString((i * IntensityGradiation).ToString("#,#.###############"), strFont, new SolidBrush(Color.Black), 0, ConvToPicBoxCoord(0, i * IntensityGradiation).Y - 6); + g.DrawLine(new Pen(Color.LightGray, 1), OriginPos.X - 8, ConvToPicBoxCoord(0, i * IntensityGradiation).Y, pictureBox.Width, ConvToPicBoxCoord(0, i * IntensityGradiation).Y); } + } - #region 座標変換関係 + #region 座標変換関係 - private PointF ConvToPicBoxCoord(double x, double y) - {//プロファイル座標をピクチャーボックスの座標系に変換 - return new PointF((float)((pictureBox.Width - OriginPos.X) / (UpperX - LowerX) * (x - LowerX)) + OriginPos.X, - (float)(pictureBox.Height - OriginPos.Y - BottomMargin - (pictureBox.Height - OriginPos.Y - BottomMargin) / (UpperY - LowerY) * (y - LowerY))); - } + private PointF ConvToPicBoxCoord(double x, double y) + {//プロファイル座標をピクチャーボックスの座標系に変換 + return new PointF((float)((pictureBox.Width - OriginPos.X) / (UpperX - LowerX) * (x - LowerX)) + OriginPos.X, + (float)(pictureBox.Height - OriginPos.Y - BottomMargin - (pictureBox.Height - OriginPos.Y - BottomMargin) / (UpperY - LowerY) * (y - LowerY))); + } - private PointF ConvToPicBoxCoord(PointD p) - {//ピクチャーボックスの座標系に変換 - return new PointF((float)((pictureBox.Width - OriginPos.X) / (UpperX - LowerX) * (p.X - LowerX)) + OriginPos.X, - (float)(pictureBox.Height - OriginPos.Y - BottomMargin - (pictureBox.Height - OriginPos.Y - BottomMargin) / (UpperY - LowerY) * (p.Y - LowerY))); - } + private PointF ConvToPicBoxCoord(PointD p) + {//ピクチャーボックスの座標系に変換 + return new PointF((float)((pictureBox.Width - OriginPos.X) / (UpperX - LowerX) * (p.X - LowerX)) + OriginPos.X, + (float)(pictureBox.Height - OriginPos.Y - BottomMargin - (pictureBox.Height - OriginPos.Y - BottomMargin) / (UpperY - LowerY) * (p.Y - LowerY))); + } - private PointD ConvToRealCoord(int x, int y) - {//マウス座標をオリジナルの座標系に変換 - return new PointD( - (double)(x - OriginPos.X) / (pictureBox.Width - OriginPos.X) * (UpperX - LowerX) + LowerX, - (double)(pictureBox.Height - y - OriginPos.Y - BottomMargin) / (pictureBox.Height - OriginPos.Y - BottomMargin) * (UpperY - LowerY) + LowerY); - } + private PointD ConvToRealCoord(int x, int y) + {//マウス座標をオリジナルの座標系に変換 + return new PointD( + (double)(x - OriginPos.X) / (pictureBox.Width - OriginPos.X) * (UpperX - LowerX) + LowerX, + (double)(pictureBox.Height - y - OriginPos.Y - BottomMargin) / (pictureBox.Height - OriginPos.Y - BottomMargin) * (UpperY - LowerY) + LowerY); + } - #endregion 座標変換関係 + #endregion 座標変換関係 - private void numericUpDownWidth_ValueChanged(object sender, EventArgs e) => RefreshTable(); + private void numericUpDownWidth_ValueChanged(object sender, EventArgs e) => RefreshTable(); - private void numericUpDownMaxLength_ValueChanged(object sender, EventArgs e) => RefreshTable(); + private void numericUpDownMaxLength_ValueChanged(object sender, EventArgs e) => RefreshTable(); - private void AtomCoordinateTable_Resize_1(object sender, EventArgs e) => RefreshTable(); - } + private void AtomCoordinateTable_Resize_1(object sender, EventArgs e) => RefreshTable(); } \ No newline at end of file diff --git a/Crystallography.Controls/Crystallography.Controls.csproj b/Crystallography.Controls/Crystallography.Controls.csproj index acd3122..640fb9e 100644 --- a/Crystallography.Controls/Crystallography.Controls.csproj +++ b/Crystallography.Controls/Crystallography.Controls.csproj @@ -4,8 +4,8 @@ Library net8.0-windows10.0.22621.0 true - 2023.12.6.0629 - 2023.12.6.0629 + 2023.12.13.0441 + 2023.12.13.0441 PerMonitorV2 true true diff --git a/Crystallography.Controls/Numeric/NumericBox.cs b/Crystallography.Controls/Numeric/NumericBox.cs index 52bba6a..310f8af 100644 --- a/Crystallography.Controls/Numeric/NumericBox.cs +++ b/Crystallography.Controls/Numeric/NumericBox.cs @@ -211,13 +211,13 @@ public string ToolTip [Category("Font && Color")] public Color TextBoxForeColor { set => textBox.ForeColor = value; get => textBox.ForeColor; } - [DefaultValue(typeof(Color), "Window")] [Category("Font && Color")] + [DefaultValue(typeof(Color), "Window")] public Color TextBoxBackColor { set => textBox.BackColor = value; get => textBox.BackColor; } - [DefaultValue(typeof(Font), "Segoe UI Symbol, 9.75pt")] [Localizable(true)] [Category("Font && Color")] + [DefaultValue(typeof(Font), "Segoe UI Symbol, 9.75pt")] /// /// font /// @@ -239,7 +239,7 @@ public Font TextFont MaximumSize = new Size(1000, textBox.Height + 5); } } - get { return textBox.Font; } + get => textBox.Font; } @@ -519,8 +519,6 @@ public void Calculate(object sender, EventArgs e) } } - - /// /// ݂numericalValueeLXg{bNX̕ݒ肷 /// @@ -559,11 +557,11 @@ internal string GetString() { text = numericalValue.ToString(DecimalPlaces >= 0 ? $"f{DecimalPlaces}" : ""); if (TrimEndZero && text.Contains('.')) - text = text.TrimEnd(new[] { '0' }).TrimEnd(new[] { '.' }); + text = text.TrimEnd(['0']).TrimEnd(['.']); text = separateThousands(text); } - if (!text.StartsWith("-") && ShowPositiveSign && text != "0") + if (!text.StartsWith('-') && ShowPositiveSign && text != "0") text = "+" + text; return text; @@ -575,7 +573,7 @@ private static string separateThousands(string valueString) if (valueString.Contains(',')) decimalPoint = ','; - var integer = valueString.Split(new[] { decimalPoint }); + var integer = valueString.Split([decimalPoint]); for (int i = integer[0].Length - 3; i > 0; i -= 3) { if (integer[0][i - 1] != '-') diff --git a/Crystallography.Controls/Numeric/NumericBox.resx b/Crystallography.Controls/Numeric/NumericBox.resx index 7a5c2ac..52b4c25 100644 --- a/Crystallography.Controls/Numeric/NumericBox.resx +++ b/Crystallography.Controls/Numeric/NumericBox.resx @@ -1,4 +1,64 @@ + + diff --git a/Crystallography/Crystal/Crystal.cs b/Crystallography/Crystal/Crystal.cs index 5634dbc..300dc32 100644 --- a/Crystallography/Crystal/Crystal.cs +++ b/Crystallography/Crystal/Crystal.cs @@ -1,6 +1,7 @@ #region using using MathNet.Numerics; using MathNet.Numerics.LinearAlgebra.Factorization; +using Microsoft.VisualBasic.Devices; using System; using System.Collections.Generic; using System.Drawing; @@ -1824,4 +1825,50 @@ public void RevertInitialCellConstants() } #endregion + + /// + /// w肵q(target)̋ߕӂɂ錴qTA΍WAAxԂ. (΍WłȂƂɒ) + /// + /// + /// nm P + /// + public List<(double X, double Y, double Z, double Distance, string Label)> Search(Atoms target, double maxLength) + { + Vector3DBase pos = MatrixReal * target.Atom[0]; + var maxLen2 = maxLength * maxLength; + var result = new List<(double X, double Y, double Z, double Distance, string Label)>(); + //܂Aׂ荇Pʊiq̌qʒuׂĒTCoordinatedAtom^̃XgɑS + for (int max = 0; max < 8; max++) + { + bool flag = false; + Parallel.For(-max, max + 1, xShift => + { + for (int yShift = -max; yShift <= max; yShift++) + for (int zShift = -max; zShift <= max; zShift++) + { + if (Math.Abs(xShift) == max || Math.Abs(yShift) == max || Math.Abs(zShift) == max) + { + foreach (var atm in Atoms) + foreach (var v in atm.Atom) + { + var diffPos = MatrixReal * (v + new Vector3DBase(xShift, yShift, zShift)) - pos; + if (maxLen2 > (diffPos ).Length2) + { + + lock (lockObj) + { + result.Add((diffPos.X, diffPos.Y, diffPos.Z, diffPos.Length, atm.Label)); + flag = true;//‚ł‚ꂽ瑱s + } + } + } + } + } + }); + if (flag == false && max > 2) + break; + } + result.Sort((a1, a2) => a1.Distance.CompareTo(a2.Distance)); + return result; + } } diff --git a/Crystallography/Crystallography.csproj b/Crystallography/Crystallography.csproj index 7d74afb..20d6e02 100644 --- a/Crystallography/Crystallography.csproj +++ b/Crystallography/Crystallography.csproj @@ -4,8 +4,8 @@ Library net8.0-windows10.0.22621.0 true - 2023.12.6.0629 - 2023.12.6.0629 + 2023.12.13.0441 + 2023.12.13.0441 7.0 diff --git a/Crystallography/Images/ImageIO.cs b/Crystallography/Images/ImageIO.cs index 08215a9..0890369 100644 --- a/Crystallography/Images/ImageIO.cs +++ b/Crystallography/Images/ImageIO.cs @@ -12,7 +12,7 @@ namespace Crystallography; public static class ImageIO { public static string[] ListOfExtension = - { + [ "img", "stl", "ccd", @@ -34,7 +34,7 @@ public static class ImageIO "png", "smv", "mrc", - }; + ]; public static string FilterString { @@ -317,12 +317,13 @@ private static bool SMV(string filename) } #endregion - #region RadIcon rawファイル + #region rawファイル (RadIcon など) public static bool RadIcon(string str) { - try + // try { - if (new FileInfo(str).Length == 6390144)//2064*1548のサイズを持つ検出器 (SACLA EH5の場合) + #region 2064*1548のサイズを持つ検出器 (SACLA EH5の場合) + if (new FileInfo(str).Length == 6390144) { var br = new BinaryReader(new FileStream(str, FileMode.Open, FileAccess.Read)); int imageWidth = 2064, imageHeight = 1548, length = imageWidth * imageHeight; @@ -346,9 +347,11 @@ public static bool RadIcon(string str) Ring.ImageType = Ring.ImageTypeEnum.RadIcon; Ring.Comments = ""; + return true; } + #endregion - //2020年に導入された、PFのRAWファイル形式 (references\ImageExsample\BL18c 柴咲さん を参考せよ) + #region 2020年に導入された、PFのRAWファイル形式 (references\ImageExsample\BL18c 柴咲さん を参考せよ) else if (Check_PF_RAW(str)) { var br = new BinaryReader(new FileStream(str, FileMode.Open, FileAccess.Read)); @@ -438,18 +441,17 @@ public static bool RadIcon(string str) return true; } - - - + #endregion + return false; } - catch (Exception e) - { - MessageBox.Show(e.Message); - return false; - } + //catch (Exception e) + //{ + // MessageBox.Show(e.Message); + // return false; + //} } #endregion diff --git a/Crystallography/Mathematics/Geometriy.cs b/Crystallography/Mathematics/Geometriy.cs index 10dc620..25c14c0 100644 --- a/Crystallography/Mathematics/Geometriy.cs +++ b/Crystallography/Mathematics/Geometriy.cs @@ -691,7 +691,43 @@ public static Vector3DBase GetCrossPoint(in double a, in double b, in double c, var y = (d * dy - c * ux + a * uz) / denom; var z = (d * dz - a * uy + b * ux) / denom; - return new Vector3D(x, y, z); + return new Vector3DBase(x, y, z); + } + + /// + /// 3 a x + b y + c z = d (@xNg(a,b,c))A_pt1pt2Ԓƌ_Ԃ. ʕa x + b y + c z + d = 0 ł͂ȂƂɒ + /// + /// + /// + /// + /// + /// + /// + /// + public static Vector3d GetCrossPoint(in double a, in double b, in double c, in double d, in V3d p1, in V3d p2) + { + //3‚̕𖞂x, y, z ߂΂悢 (2020/02/04C) + // a x + b y + c z = d + //(y1 - y2) x - (x1 - x2) y = x2 y1 - x1 y2 + //(z1 - z2) y - (y1 - y2) z = y2 z1 - y1 z2 + + //double denom = a * (p1.X - p2.X) + b * (p1.Y - p2.Y) + c * (p1.Z - p2.Z); + //double x = (d * (p1.X - p2.X) - b * (p1.X * p2.Y - p1.Y * p2.X) - c * (p1.X * p2.Z - p1.Z * p2.X)) / denom; + //double y = (d * (p1.Y - p2.Y) - c * (p1.Y * p2.Z - p1.Z * p2.Y) - a * (p1.Y * p2.X - p1.X * p2.Y)) / denom; + //double z = (d * (p1.Z - p2.Z) - a * (p1.Z * p2.X - p1.X * p2.Z) - b * (p1.Z * p2.Y - p1.Y * p2.Z)) / denom; + + double dx = p1.X - p2.X, dy = p1.Y - p2.Y, dz = p1.Z - p2.Z; + + var uz = p1.X * p2.Y - p1.Y * p2.X; + var ux = p1.Y * p2.Z - p1.Z * p2.Y; + var uy = p1.Z * p2.X - p1.X * p2.Z; + + var denom = a * dx + b * dy + c * dz; + var x = (d * dx - b * uz + c * uy) / denom; + var y = (d * dy - c * ux + a * uz) / denom; + var z = (d * dz - a * uy + b * ux) / denom; + + return new V3d(x, y, z); } @@ -829,11 +865,11 @@ private static PointD[] getCrossPoint(PointD p1, PointD p2, RectangleD rect) double c = a * rect.X + b; if (c < rect.Y) - return new[] { new PointD((rect.Y - b) / a, rect.Y) }; + return [new PointD((rect.Y - b) / a, rect.Y)]; else if (c > rect.UpperY) - return new[] { new PointD((rect.UpperY - b) / a, rect.UpperY) }; + return [new PointD((rect.UpperY - b) / a, rect.UpperY)]; else - return new[] { new PointD(rect.X, c) }; + return [new PointD(rect.X, c)]; } else//p1p2͈͊ÔƂ { @@ -842,9 +878,9 @@ private static PointD[] getCrossPoint(PointD p1, PointD p2, RectangleD rect) if (p1.X >= rect.X && p1.X <= rect.UpperX)//҂X͔͈͓AYꂼƉ𒴂Ăꍇ { if (p1.Y < rect.Y && rect.UpperY < p2.Y) - return new[] { new PointD(p1.X, rect.Y), new PointD(p1.X, rect.UpperY) }; + return [new PointD(p1.X, rect.Y), new PointD(p1.X, rect.UpperY)]; else if (p2.Y < rect.Y && rect.UpperY < p1.Y) - return new[] { new PointD(p1.X, rect.UpperY), new PointD(p1.X, rect.Y) }; + return [new PointD(p1.X, rect.UpperY), new PointD(p1.X, rect.Y)]; } else return null; @@ -852,7 +888,7 @@ private static PointD[] getCrossPoint(PointD p1, PointD p2, RectangleD rect) //4‚̌_߂ - var temp = new List(new[] { + List temp = new(new[] { new PointD(rect.X, a * rect.X + b), new PointD(rect.UpperX, a * rect.UpperX + b), new PointD((rect.Y - b) / a, rect.Y), @@ -884,11 +920,11 @@ public static double GetLengthFromPlane(double a, double b, double c, double d, } /// - /// _Wŏ@ɂ镽ʃp[^double[]{a,b,c,d} (AAʕ a x + b y + c z + d = 0) Ԃ + /// _Wŏ@ɂ镽ʃp[^A, B, C, D (AAʕ a x + b y + c z + d = 0) Ԃ /// /// /// double[]{a,b,c,d} (AAʕ a x + b y + c z + d = 0) - public static double[] GetPlaneEquationFromPoints(IEnumerable points) + public static (double A, double B, double C, double D ) GetPlaneEquationFromPoints(IEnumerable points) { //http://sysplan.nams.kyushu-u.ac.jp/gen/edu/Algorithms/PlaneFitting/index.html //pdfCrystallograpy/tH_ @@ -903,7 +939,7 @@ public static double[] GetPlaneEquationFromPoints(IEnumerable poin var index = evd.EigenValues.AbsoluteMinimumIndex(); double a = evd.EigenVectors[0, index], b = evd.EigenVectors[1, index], c = evd.EigenVectors[2, index], d = -(a * ave.X + b * ave.Y + c * ave.Z); - return new double[] { a, b, c, d }; + return (a, b, c, d); } /// @@ -911,7 +947,7 @@ public static double[] GetPlaneEquationFromPoints(IEnumerable poin /// /// /// double[]{a,b,c,d} (AAʕ a x + b y + c z + d = 0) - public static double[] GetPlaneEquationFromPoints(IEnumerable points) + public static (double A, double B, double C, double D) GetPlaneEquationFromPoints(IEnumerable points) { //http://sysplan.nams.kyushu-u.ac.jp/gen/edu/Algorithms/PlaneFitting/index.html //pdfCrystallograpy/tH_ @@ -931,7 +967,7 @@ public static double[] GetPlaneEquationFromPoints(IEnumerable p var index = evd.EigenValues.AbsoluteMinimumIndex(); double a = evd.EigenVectors[0, index], b = evd.EigenVectors[1, index], c = evd.EigenVectors[2, index], d = -(a * ave.X + b * ave.Y + c * ave.Z); - return new double[] { a, b, c, d }; + return (a, b, c, d); } @@ -961,101 +997,93 @@ public static bool Enclosed(double[][] bounds) /// /// EʂɂĐ؂ꂽp`̒_W߂. /// - /// ؂ (double[4], a x + b y + c z + d = 0) + /// ؂ (double[4], a x + b y + c z + d = 0) /// E (double[4], a x + b y + c z + d >= 0 ) /// - public static double[][] GetClippedPolygon(double[] plane, double[][] bounds) + public static double[][] GetClippedPolygon(double[] p, double[][] bounds) { - if(bounds.Length == 0)return null; + if (bounds.Length == 0) return null; - List pts; + List pts; - if (bounds.Length < 250) + if (bounds.Length < 250)//boundsȂꍇ͐U@ʼn { - pts = new List(); + pts = []; for (int i = 0; i < bounds.Length; i++) { - var mtx = new Matrix3D(plane[0], bounds[i][0], 0, plane[1], bounds[i][1], 0, plane[2], bounds[i][2], 0); + var mtx = new Matrix3D(p[0], bounds[i][0], 0, p[1], bounds[i][1], 0, p[2], bounds[i][2], 0); for (int j = i + 1; j < bounds.Length; j++) { mtx.E31 = bounds[j][0]; mtx.E32 = bounds[j][1]; mtx.E33 = bounds[j][2]; if (Math.Abs(mtx.Determinant()) > 0.0000000001) { - var pt = mtx.Inverse() * new Vector3DBase(-plane[3], -bounds[i][3], -bounds[j][3]); - if (bounds.All(b => b[0] * pt.X + b[1] * pt.Y + b[2] * pt.Z + b[3] > -0.0000000001) && pts.All(p => (p - pt).Length2 > 0.0000000001)) + var pt = (mtx.Inverse() * (-p[3], -bounds[i][3], -bounds[j][3])).ToOpenTK(); + if (bounds.All(b => b[0] * pt.X + b[1] * pt.Y + b[2] * pt.Z + b[3] > -0.0000000001) && pts.All(p => (p - pt).LengthSquared > 0.0000000001)) pts.Add(pt); } } } } - else + else//boundsꍇ́A傫ȋ`Xɐ؂悤ȃASY { + var p2 = p[0] * p[0] + p[1] * p[1] + p[2] * p[2]; + //planéA\ɑ傫ʐς4_pӂ var max = bounds.Max(b => b[3]); - Vector3DBase temp1 = new(plane[0], plane[1], plane[2]), temp2 = new(0, 0, 1); + Vector3DBase temp1 = new(p[0], p[1], p[2]), temp2 = new(0, 0, 1); var rotAngle = Vector3DBase.AngleBetVectors(temp1, temp2); var rotAxis = Vector3DBase.VectorProduct(temp1, temp2); - var rot = Math.Abs(rotAngle - Math.PI) < 1E-10 ? Matrix3D.Rot(new Vector3DBase(1, 0, 0), Math.PI) : Matrix3D.Rot(rotAxis, -rotAngle); + var rot = Math.Abs(rotAngle - Math.PI) < 1E-10 ? Matrix3D.Rot((1, 0, 0), Math.PI) : Matrix3D.Rot(rotAxis, -rotAngle); - pts = [rot * new Vector3DBase(max, max, -plane[3]), rot * new Vector3DBase(-max, max, -plane[3]), rot * new Vector3DBase(-max, -max, -plane[3]), rot * new Vector3DBase(max, -max, -plane[3])]; + pts = [(rot * (max, max, -p[3])).ToOpenTK(), (rot * (-max, max, -p[3])).ToOpenTK(), (rot * (-max, -max, -p[3])).ToOpenTK(), (rot * (max, -max, -p[3])).ToOpenTK()]; //boundsɂĐ؂WvZAV_WĂ - foreach (var b in bounds.Where(b => !(b[0] == plane[0] && b[1] == plane[1] && b[2] == plane[2] && b[3] == plane[3]))) + foreach (var b in bounds.Where(b => !(b[0] == p[0] && b[1] == p[1] && b[2] == p[2] && b[3] == p[3]))) { - var angle = Vector3DBase.AngleBetVectors(new Vector3DBase(b[0], b[1], b[2]), new Vector3DBase(plane[0], plane[1], plane[2])); + var b2 = b[0] * b[0] + b[1] * b[1] + b[2] * b[2]; + var pb = b[0] * p[0] + b[1] * p[1] + b[2] * p[2]; - if (Math.Abs(angle) > 1E-10 && Math.Abs(angle - Math.PI) > 1E-10) + if (pb * pb / p2 / b2 < 1 - 1E-10)// bplanesł͂Ȃꍇ { + var ptsNew = new List(pts.Count + 1); + var v1 = pts[^1]; + var r1 = v1.X * b[0] + v1.Y * b[1] + v1.Z * b[2] + b[3]; for (int i = 0; i < pts.Count; i++) { - Vector3DBase v1 = pts[i], v2 = i < pts.Count - 1 ? pts[i + 1] : pts[0]; - - double r1 = v1.X * b[0] + v1.Y * b[1] + v1.Z * b[2] + b[3], r2 = v2.X * b[0] + v2.Y * b[1] + v2.Z * b[2] + b[3]; + if (r1 > -1E-10) + ptsNew.Add(v1); - if ((r1 < 0 && r2 > 0) || (r1 > 0 && r2 < 0))//v1v2̊Ԃ𕽖bʂƂA + var v2 = pts[i]; + var r2 = v2.X * b[0] + v2.Y * b[1] + v2.Z * b[2] + b[3]; + + if (Math.Abs(r1) > 1E-10 && Math.Abs(r2) > 1E-10 && r1 * r2 < 0) //v1v2̊Ԃ𕽖bʂƂA { var pt = GetCrossPoint(b[0], b[1], b[2], -b[3], v1, v2);//d=b[3]̕ɒ - pts.Insert(i + 1, pt); - i++; + if ((pt - v1).LengthSquared > 1E-10 && (pt - v2).LengthSquared > 1E-10) + ptsNew.Add(pt); } + v1 = v2; + r1 = r2; } - for (int i = 0; i < pts.Count; i++) - if (pts[i].X * b[0] + pts[i].Y * b[1] + pts[i].Z * b[2] + b[3] < -1E-10) - pts.RemoveAt(i--); - - for (int i = 0; i < pts.Count; i++) - for (int j = i + 1; j < pts.Count; j++) - if ((pts[i] - pts[j]).Length2 < 1E-10) - pts.RemoveAt(j--); + if (ptsNew.Count < 3) + return null; + pts = ptsNew; } + else if ((pb > 0 && b[3] < p[3]) || (pb < 0 && b[3] < p[3])) //bPlanesȏꍇA@̌ɒӂnullԂ + return null; } } - return pts.Select(p => new double[] { p.X, p.Y, p.Z }).ToArray(); - } - const double Th = 1E-9; - private static M3d CreateRotationToZ(V3d v) - { - v.Normalize(); - if (Math.Abs(v.Z - 1) < Th) - return M3d.Identity; - else if (Math.Abs(v.Z + 1) < Th) - return M3d.CreateRotationX(Math.PI); - else - return M3d.CreateFromAxisAngle(V3d.Cross(new V3d(0,0,1), v), V3d.CalculateAngle(new V3d(0, 0, 1), v)); + return pts.Select(p => new double[] { p.X, p.Y, p.Z }).ToArray(); } - /// /// EʂɂĐ؂ꂽp`̒_W߂. /// /// ؂ʂ̃CfbNX /// E (i͏) (double[4], a x + b y + c z + d >= 0 ) /// - public static double[][] GetClippedPolygon(int i, double[][] bounds) - { - return GetClippedPolygon(bounds[i], bounds); - } + public static double[][] GetClippedPolygon(int i, double[][] bounds) => GetClippedPolygon(bounds[i], bounds); /// /// xNga1 => xNgb1 xNga2 => xNgb2Ɏʂ悤ȉ]s߂. a1,a2,b1,b2̒1łȂĂ\Ȃi֐ŋKij diff --git a/Crystallography/Matrix.cs b/Crystallography/Matrix.cs index 70120f8..d53b92c 100644 --- a/Crystallography/Matrix.cs +++ b/Crystallography/Matrix.cs @@ -229,6 +229,7 @@ public Matrix3D(Matrix3D m) public static Vector3DBase operator *(Matrix3D m, Vector3DBase v) => new(m.E11 * v.X + m.E12 * v.Y + m.E13 * v.Z, m.E21 * v.X + m.E22 * v.Y + m.E23 * v.Z, m.E31 * v.X + m.E32 * v.Y + m.E33 * v.Z); + /// /// Matrix3Dƃ^v(x,y,z)̏Z. (x,y,z)c̃xNgƂČvZB /// @@ -294,13 +295,22 @@ public static Matrix3D Inverse(Matrix3D m) public static Matrix3D ExchangeZ_X_Y(Matrix3D m) => new(-m.E31, m.E11, -m.E21, -m.E32, m.E12, -m.E22, -m.E33, m.E13, -m.E23); + + /// + /// xNgv̎̕,theta]s𐶐 + /// + /// ] + /// ]px + /// + public static Matrix3D Rot(Vector3DBase v, in double theta) => Rot((v.X, v.Y, v.Z), theta); + /// /// xNgv̎̕,theta]s𐶐 /// /// ] /// ]px /// - public static Matrix3D Rot(Vector3DBase v, in double theta) + public static Matrix3D Rot((double X, double Y, double Z) v, in double theta) { //Vx*Vx*(1-cos) + cos Vx*Vy*(1-cos) - Vz*sin Vz*Vx*(1-cos) + Vy*sin //Vx*Vy*(1-cos) + Vz*sin Vy*Vy*(1-cos) + cos Vy*Vz*(1-cos) - Vx*sin @@ -571,6 +581,11 @@ public Vector3DBase(double x, double y, double z) X = x; Y = y; Z = z; } + public Vector3DBase((double X, double Y, double Z) v) + { + X = v.X; Y = v.Y; Z = v.Z; + } + public Vector3DBase(double[] v) { if (v.Length == 3) @@ -695,6 +710,12 @@ internal static Vector3DBase Normarize(Vector3DBase v) return l > 0 ? new Vector3DBase(v.X / l, v.Y / l, v.Z / l) : v; } + internal static (double X, double Y, double Z) Normarize((double X, double Y, double Z) v) + { + double l = Math.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z); + return l > 0 ? (v.X / l, v.Y / l, v.Z / l) : (v); + } + public Vector3DBase Normarize() => Normarize(this); public void NormarizeThis() @@ -740,7 +761,8 @@ public static double AngleBetVectors(in Vector3DBase v1, in Vector3DBase v2) var aCos = Normarize(v1) * Normarize(v2); if (aCos > 1) return 0; - else return aCos < -1 ? Math.PI / 2 : Math.Acos(aCos); + else + return aCos < -1 ? Math.PI / 2 : Math.Acos(aCos); } ///