// 将此 Frame 对象运动指定的时长(秒)。 public void NextMoment(double seconds) { if (_Frozen) { throw new InvalidOperationException(); } if (double.IsNaN(seconds) || double.IsInfinity(seconds) || seconds <= 0) { throw new ArgumentOutOfRangeException(); } // _Time += seconds; if (_Particles.Length > 0) { for (int i = 0; i < _Particles.Length; i++) { _Particles[i].RemoveForce(); } for (int i = 0; i < _Particles.Length; i++) { for (int j = i + 1; j < _Particles.Length; j++) { PointD3D distance = _Particles[j].Location - _Particles[i].Location; double distanceModule = distance.Module; if (distanceModule > 0) { double radiusSum = _Particles[i].Radius + _Particles[j].Radius; double dist = Math.Max(distanceModule, radiusSum); double distSquared = dist * dist; PointD3D force = (_GravitationalConstant * _Particles[i].Mass * _Particles[j].Mass / distSquared) * distance.Normalize; if (distanceModule < radiusSum) { force *= distanceModule / radiusSum; } _Particles[i].AddForce(force); _Particles[j].AddForce(force.Opposite); } } } for (int i = 0; i < _Particles.Length; i++) { _Particles[i].NextMoment(seconds); } } }
private void AffineTransform(ref Com.PointD3D Pt, Com.PointD3D Origin, Com.Matrix AffineMatrix) { // // 将一个 3D 坐标以指定点为新的原点进行仿射变换。 // Pt -= Origin; Pt.AffineTransform(AffineMatrix); Pt += Origin; }
// 移除在此 Particle 对象上施加的所有作用力。 public void RemoveForce() { if (_Frozen) { throw new InvalidOperationException(); } // _Force = PointD3D.Zero; }
// 在此 Particle 对象上施加一个作用力(牛顿)。 public void AddForce(PointD3D force) { if (_Frozen) { throw new InvalidOperationException(); } if (force.IsNaNOrInfinity) { throw new ArgumentOutOfRangeException(); } // _Force += force; }
private void Label_Sz_MouseMove(object sender, MouseEventArgs e) { // // 鼠标经过 Label_Sz。 // if (AdjustNow && !BackgroundWorker_RepaintBmpDelay.IsBusy) { double ratio = Math.Max(0.01, 1 + (e.X - CursorX) * RatioPerPixel); ((Label)sender).Text = "× " + ratio.ToString("F2"); CubeSize = Com.PointD3D.Max(new Com.PointD3D(0.001, 0.001, 0.001), new Com.PointD3D(CubeSizeCopy.X, CubeSizeCopy.Y, CubeSizeCopy.Z * ratio).Normalize); BackgroundWorker_RepaintBmpDelay.RunWorkerAsync(); } }
// 将此 Particle 对象运动指定的时长(秒)。 public void NextMoment(double seconds) { if (_Frozen) { throw new InvalidOperationException(); } if (double.IsNaN(seconds) || double.IsInfinity(seconds) || seconds <= 0) { throw new ArgumentOutOfRangeException(); } // PointD3D acceleration = Acceleration; _Location += (_Velocity + acceleration * (seconds / 2)) * seconds; _Velocity += acceleration * seconds; }
private ParticleExtAttr _Attr; // 其他属性。 private Particle(double mass, double radius, PointD3D location, PointD3D velocity, PointD3D force, ParticleExtAttr attr) { if ((double.IsNaN(mass) || double.IsInfinity(mass) || mass <= 0) || (double.IsNaN(radius) || double.IsInfinity(radius) || radius <= 0) || location.IsNaNOrInfinity || velocity.IsNaNOrInfinity || force.IsNaNOrInfinity) { throw new ArgumentOutOfRangeException(); } // _Frozen = false; _Mass = mass; _Radius = radius; _Location = location; _Velocity = velocity; _Force = force; _Attr = attr; }
private void Label_Control_MouseDown(object sender, MouseEventArgs e) { // // 鼠标按下 Label_Control。 // if (e.Button == MouseButtons.Left) { ((Label)sender).BackColor = Me.RecommendColors.Button_INC.ToColor(); ((Label)sender).Cursor = Cursors.SizeWE; CubeSizeCopy = CubeSize; AffineMatrix3DCopy = AffineMatrix3D.Copy(); IlluminationDirectionCopy = IlluminationDirection; ExposureCopy = Exposure; CursorX = e.X; AdjustNow = true; } }
// 在此 Particle 对象上施加若干个作用力(牛顿)。 public void AddForce(params PointD3D[] forces) { if (_Frozen) { throw new InvalidOperationException(); } for (int i = 0; i < forces.Length; i++) { if (forces[i].IsNaNOrInfinity) { throw new ArgumentOutOfRangeException(); } } // for (int i = 0; i < forces.Length; i++) { _Force += forces[i]; } }
public Particle(double mass, double radius, PointD3D location, PointD3D velocity, Color color) : this(mass, radius, location, velocity, PointD3D.Zero, new ParticleExtAttr(mass * 0.75 / Math.PI / (radius * radius * radius), color)) { }
private Bitmap GetProjectionOfCube(Com.PointD3D CubeSize, Color CubeColor, Com.Matrix AffineMatrix, Com.PointD3D IlluminationDirection, double Exposure, Views View, SizeF ImageSize) { // // 获取立方体的投影。 // double CubeDiag = Math.Min(ImageSize.Width, ImageSize.Height); CubeSize = CubeSize.Normalize * CubeDiag; Bitmap PrjBmp = new Bitmap(Math.Max(1, (int)ImageSize.Width), Math.Max(1, (int)ImageSize.Height)); // Com.PointD3D CubeCenter = new Com.PointD3D(0, 0, 0); Com.PointD3D P3D_000 = new Com.PointD3D(0, 0, 0); Com.PointD3D P3D_100 = new Com.PointD3D(1, 0, 0); Com.PointD3D P3D_010 = new Com.PointD3D(0, 1, 0); Com.PointD3D P3D_110 = new Com.PointD3D(1, 1, 0); Com.PointD3D P3D_001 = new Com.PointD3D(0, 0, 1); Com.PointD3D P3D_101 = new Com.PointD3D(1, 0, 1); Com.PointD3D P3D_011 = new Com.PointD3D(0, 1, 1); Com.PointD3D P3D_111 = new Com.PointD3D(1, 1, 1); P3D_000 = (P3D_000 - 0.5) * CubeSize + CubeCenter; P3D_100 = (P3D_100 - 0.5) * CubeSize + CubeCenter; P3D_010 = (P3D_010 - 0.5) * CubeSize + CubeCenter; P3D_110 = (P3D_110 - 0.5) * CubeSize + CubeCenter; P3D_001 = (P3D_001 - 0.5) * CubeSize + CubeCenter; P3D_101 = (P3D_101 - 0.5) * CubeSize + CubeCenter; P3D_011 = (P3D_011 - 0.5) * CubeSize + CubeCenter; P3D_111 = (P3D_111 - 0.5) * CubeSize + CubeCenter; Com.PointD3D RotateCenter3D = CubeCenter; AffineTransform(ref P3D_000, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_100, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_010, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_110, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_001, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_101, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_011, RotateCenter3D, AffineMatrix); AffineTransform(ref P3D_111, RotateCenter3D, AffineMatrix); // double TrueLenDist3D = new Com.PointD(Screen.PrimaryScreen.Bounds.Size).Module; Com.PointD3D PrjCenter3D = CubeCenter; switch (View) { case Views.XY: PrjCenter3D.Z -= (TrueLenDist3D + CubeDiag / 2); break; case Views.YZ: PrjCenter3D.X -= (TrueLenDist3D + CubeDiag / 2); break; case Views.ZX: PrjCenter3D.Y -= (TrueLenDist3D + CubeDiag / 2); break; } Func <Com.PointD3D, Com.PointD3D, double, Com.PointD> GetProject3D = (Pt, PrjCenter, TrueLenDist) => { switch (View) { case Views.XY: return(Pt.ProjectToXY(PrjCenter, TrueLenDist)); case Views.YZ: return(Pt.ProjectToYZ(PrjCenter, TrueLenDist)); case Views.ZX: return(Pt.ProjectToZX(PrjCenter, TrueLenDist)); default: return(Com.PointD.NaN); } }; Com.PointD P2D_000 = GetProject3D(P3D_000, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_100 = GetProject3D(P3D_100, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_010 = GetProject3D(P3D_010, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_110 = GetProject3D(P3D_110, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_001 = GetProject3D(P3D_001, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_101 = GetProject3D(P3D_101, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_011 = GetProject3D(P3D_011, PrjCenter3D, TrueLenDist3D); Com.PointD P2D_111 = GetProject3D(P3D_111, PrjCenter3D, TrueLenDist3D); Com.PointD BitmapCenter = new Com.PointD(PrjBmp.Size) / 2; PointF P_000 = (P2D_000 + BitmapCenter).ToPointF(); PointF P_100 = (P2D_100 + BitmapCenter).ToPointF(); PointF P_010 = (P2D_010 + BitmapCenter).ToPointF(); PointF P_110 = (P2D_110 + BitmapCenter).ToPointF(); PointF P_001 = (P2D_001 + BitmapCenter).ToPointF(); PointF P_101 = (P2D_101 + BitmapCenter).ToPointF(); PointF P_011 = (P2D_011 + BitmapCenter).ToPointF(); PointF P_111 = (P2D_111 + BitmapCenter).ToPointF(); // List <Com.PointD3D[]> Element3D = new List <Com.PointD3D[]>(18) { // XY 面 new Com.PointD3D[] { P3D_000, P3D_010, P3D_110, P3D_100 }, new Com.PointD3D[] { P3D_001, P3D_011, P3D_111, P3D_101 }, // YZ 面 new Com.PointD3D[] { P3D_000, P3D_001, P3D_011, P3D_010 }, new Com.PointD3D[] { P3D_100, P3D_101, P3D_111, P3D_110 }, // ZX 面 new Com.PointD3D[] { P3D_000, P3D_001, P3D_101, P3D_100 }, new Com.PointD3D[] { P3D_010, P3D_011, P3D_111, P3D_110 }, // X 棱 new Com.PointD3D[] { P3D_000, P3D_100 }, new Com.PointD3D[] { P3D_010, P3D_110 }, new Com.PointD3D[] { P3D_001, P3D_101 }, new Com.PointD3D[] { P3D_011, P3D_111 }, // Y 棱 new Com.PointD3D[] { P3D_000, P3D_010 }, new Com.PointD3D[] { P3D_100, P3D_110 }, new Com.PointD3D[] { P3D_001, P3D_011 }, new Com.PointD3D[] { P3D_101, P3D_111 }, // Z 棱 new Com.PointD3D[] { P3D_000, P3D_001 }, new Com.PointD3D[] { P3D_100, P3D_101 }, new Com.PointD3D[] { P3D_010, P3D_011 }, new Com.PointD3D[] { P3D_110, P3D_111 } }; List <PointF[]> Element2D = new List <PointF[]>(18) { // XY 面 new PointF[] { P_000, P_010, P_110, P_100 }, new PointF[] { P_001, P_011, P_111, P_101 }, // YZ 面 new PointF[] { P_000, P_001, P_011, P_010 }, new PointF[] { P_100, P_101, P_111, P_110 }, // ZX 面 new PointF[] { P_000, P_001, P_101, P_100 }, new PointF[] { P_010, P_011, P_111, P_110 }, // X 棱 new PointF[] { P_000, P_100 }, new PointF[] { P_010, P_110 }, new PointF[] { P_001, P_101 }, new PointF[] { P_011, P_111 }, // Y 棱 new PointF[] { P_000, P_010 }, new PointF[] { P_100, P_110 }, new PointF[] { P_001, P_011 }, new PointF[] { P_101, P_111 }, // Z 棱 new PointF[] { P_000, P_001 }, new PointF[] { P_100, P_101 }, new PointF[] { P_010, P_011 }, new PointF[] { P_110, P_111 } }; // List <double> IlluminationIntensity = new List <double>(Element3D.Count); double Exp = Math.Max(-2, Math.Min(Exposure / 50, 2)); if (IlluminationDirection.IsZero) { for (int i = 0; i < 6; i++) { IlluminationIntensity.Add(Exp); } for (int i = 6; i < Element3D.Count; i++) { IlluminationIntensity.Add((Math.Sqrt(2) / 2) * (Exp + 1) + (Exp - 1)); } } else { List <Com.PointD3D> NormalVector = new List <Com.PointD3D>(6) { // XY 面 new Com.PointD3D(0, 0, -1), new Com.PointD3D(0, 0, 1), // YZ 面 new Com.PointD3D(-1, 0, 0), new Com.PointD3D(1, 0, 0), // ZX 面 new Com.PointD3D(0, -1, 0), new Com.PointD3D(0, 1, 0), }; Com.PointD3D NewOrigin = new Com.PointD3D(0, 0, 0).AffineTransformCopy(AffineMatrix); for (int i = 0; i < NormalVector.Count; i++) { NormalVector[i] = NormalVector[i].AffineTransformCopy(AffineMatrix) - NewOrigin; } List <double> Angle = new List <double>(NormalVector.Count); for (int i = 0; i < NormalVector.Count; i++) { Angle.Add(IlluminationDirection.AngleFrom(NormalVector[i])); } for (int i = 0; i < Angle.Count; i++) { double A = Angle[i]; double CosA = Math.Cos(A); double CosSqrA = CosA * CosA; double _IlluminationIntensity = (A < Math.PI / 2 ? -CosSqrA : (A > Math.PI / 2 ? CosSqrA : 0)); if (CubeColor.A < 255 && A != Math.PI / 2) { double Transmittance = 1 - (double)CubeColor.A / 255; if (A < Math.PI / 2) { _IlluminationIntensity += (Transmittance * Math.Abs(CosA) * CosSqrA); } else { _IlluminationIntensity -= ((1 - Transmittance) * (1 - Math.Abs(CosA)) * CosSqrA); } } _IlluminationIntensity += Exp; IlluminationIntensity.Add(_IlluminationIntensity); } for (int i = 6; i < Element3D.Count; i++) { double _IlluminationIntensity = 0; int Num = 0; for (int j = 0; j < 6; j++) { bool Flag = true; foreach (Com.PointD3D P in Element3D[i]) { if (!Element3D[j].Contains(P)) { Flag = false; break; } } if (Flag) { _IlluminationIntensity += IlluminationIntensity[j]; Num++; } } _IlluminationIntensity = (Math.Sqrt(2) / 2) * (_IlluminationIntensity / Num + 1) + (Exp - 1); IlluminationIntensity.Add(_IlluminationIntensity); } } for (int i = 0; i < IlluminationIntensity.Count; i++) { IlluminationIntensity[i] = Math.Max(-1, Math.Min(IlluminationIntensity[i], 1)); } // List <Color> ElementColor = new List <Color>(IlluminationIntensity.Count); for (int i = 0; i < IlluminationIntensity.Count; i++) { switch (i) { case 6: ElementColor.Add(Colors.X); break; case 10: ElementColor.Add(Colors.Y); break; case 14: ElementColor.Add(Colors.Z); break; default: { double _IlluminationIntensity = IlluminationIntensity[i]; if (_IlluminationIntensity == 0) { ElementColor.Add(CubeColor); } else { Com.ColorX EColor = new Com.ColorX(CubeColor); if (_IlluminationIntensity < 0) { EColor.Lightness_HSL += EColor.Lightness_HSL * _IlluminationIntensity; } else { EColor.Lightness_HSL += (100 - EColor.Lightness_HSL) * _IlluminationIntensity; } ElementColor.Add(EColor.ToColor()); } } break; } } // List <double> ElementZAvg = new List <double>(Element3D.Count); for (int i = 0; i < Element3D.Count; i++) { Com.PointD3D[] Element = Element3D[i]; double ZAvg = 0; foreach (Com.PointD3D P in Element) { switch (View) { case Views.XY: ZAvg += P.Z; break; case Views.YZ: ZAvg += P.X; break; case Views.ZX: ZAvg += P.Y; break; } } ZAvg /= Element.Length; ElementZAvg.Add(ZAvg); } List <int> ElementIndex = new List <int>(ElementZAvg.Count); for (int i = 0; i < ElementZAvg.Count; i++) { ElementIndex.Add(i); } for (int i = 0; i < ElementZAvg.Count; i++) { for (int j = i + 1; j < ElementZAvg.Count; j++) { if (ElementZAvg[ElementIndex[i]] < ElementZAvg[ElementIndex[j]] || (ElementZAvg[ElementIndex[i]] <= ElementZAvg[ElementIndex[j]] + 2F && Element2D[ElementIndex[i]].Length < Element2D[ElementIndex[j]].Length)) { int Temp = ElementIndex[i]; ElementIndex[i] = ElementIndex[j]; ElementIndex[j] = Temp; } } } // using (Graphics Grph = Graphics.FromImage(PrjBmp)) { Grph.SmoothingMode = SmoothingMode.AntiAlias; // for (int i = 0; i < ElementIndex.Count; i++) { int EIndex = ElementIndex[i]; Color EColor = ElementColor[EIndex]; if (!EColor.IsEmpty && EColor.A > 0) { PointF[] Element = Element2D[EIndex]; if (Element.Length >= 3) { try { using (SolidBrush Br = new SolidBrush(EColor)) { Grph.FillPolygon(Br, Element); } } catch { } } else if (Element.Length == 2) { double PrjZ = 0; switch (View) { case Views.XY: PrjZ = PrjCenter3D.Z; break; case Views.YZ: PrjZ = PrjCenter3D.X; break; case Views.ZX: PrjZ = PrjCenter3D.Y; break; } float EdgeWidth = (TrueLenDist3D == 0 ? 2F : (float)(TrueLenDist3D / (ElementZAvg[EIndex] - PrjZ) * 2F)); try { Brush Br; Func <Color, double, int> GetAlpha = (Cr, Z) => { int Alpha; if (TrueLenDist3D == 0) { Alpha = Cr.A; } else { if (Z - PrjZ <= TrueLenDist3D) { Alpha = Cr.A; } else { Alpha = (int)Math.Max(0, Math.Min(TrueLenDist3D / (Z - PrjZ) * Cr.A, 255)); } } if (EdgeWidth < 1) { Alpha = (int)(Alpha * EdgeWidth); } return(Alpha); }; if (Com.PointD.DistanceBetween(new Com.PointD(Element[0]), new Com.PointD(Element[1])) > 1) { int Alpha0 = 0, Alpha1 = 0; switch (View) { case Views.XY: { Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].Z); Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].Z); } break; case Views.YZ: { Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].X); Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].X); } break; case Views.ZX: { Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].Y); Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].Y); } break; } Br = new LinearGradientBrush(Element[0], Element[1], Color.FromArgb(Alpha0, EColor), Color.FromArgb(Alpha1, EColor)); } else { int Alpha = GetAlpha(EColor, ElementZAvg[EIndex]); Br = new SolidBrush(Color.FromArgb(Alpha, EColor)); } using (Pen Pn = new Pen(Br, EdgeWidth)) { Grph.DrawLines(Pn, Element); } if (Br != null) { Br.Dispose(); } } catch { } } } } // Func <Com.PointD3D, int, int, int> GetAlphaOfPoint = (Pt, MinAlpha, MaxAlpha) => { switch (View) { case Views.XY: return((int)Math.Max(0, Math.Min(((Pt.Z - CubeCenter.Z) / CubeDiag + 0.5) * (MinAlpha - MaxAlpha) + MaxAlpha, 255))); case Views.YZ: return((int)Math.Max(0, Math.Min(((Pt.X - CubeCenter.X) / CubeDiag + 0.5) * (MinAlpha - MaxAlpha) + MaxAlpha, 255))); case Views.ZX: return((int)Math.Max(0, Math.Min(((Pt.Y - CubeCenter.Y) / CubeDiag + 0.5) * (MinAlpha - MaxAlpha) + MaxAlpha, 255))); default: return(0); } }; Grph.DrawString("X", new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Color.FromArgb(GetAlphaOfPoint(P3D_100, 64, 192), Colors.X)), P_100); Grph.DrawString("Y", new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Color.FromArgb(GetAlphaOfPoint(P3D_010, 64, 192), Colors.Y)), P_010); Grph.DrawString("Z", new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Color.FromArgb(GetAlphaOfPoint(P3D_001, 64, 192), Colors.Z)), P_001); // string ViewName = string.Empty; switch (View) { case Views.XY: ViewName = "XY 视图 (主视图)"; break; case Views.YZ: ViewName = "YZ 视图"; break; case Views.ZX: ViewName = "ZX 视图"; break; } Grph.DrawString(ViewName, new Font("微软雅黑", 10F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Colors.Text), new PointF(Math.Max(0, (PrjBmp.Width - PrjBmp.Height) / 4), Math.Max(0, (PrjBmp.Height - PrjBmp.Width) / 4))); // Grph.DrawRectangle(new Pen(Color.FromArgb(64, Colors.Border), 1F), new Rectangle(new Point(-1, -1), PrjBmp.Size)); } return(PrjBmp); }