public void CrossProduct() { { var v0 = new v8 <Motion>(1, 1, 1, 2, 2, 2); var v1 = new v8 <Motion>(-1, -2, -3, -4, -5, -6); var r0 = Math_.Cross(v0, v1); var r1 = Math_.CPM(v0) * v1; Assert.True(Math_.FEql(r0, r1)); } { var v0 = new v8 <Force>(1, 1, 1, 2, 2, 2); var v1 = new v8 <Force>(-1, -2, -3, -4, -5, -6); var r0 = Math_.Cross(v0, v1); var r1 = Math_.CPM(v0) * v1; Assert.True(Math_.FEql(r0, r1)); } { // Test: vx* == -Transpose(vx) var rng = new Random(321); var v = v8 <IVectorSpace> .Random(-5f, +5f, rng); var m0 = Math_.CPM(v.Cast <Motion>()); // vx var m1 = Math_.CPM(v.Cast <Force>()); // vx* var m2 = Math_.Transpose(m1); var m3 = (-m2).Cast <Motion, Motion>(); Assert.True(Math_.FEql(m0, m3)); } }
public void Basic() { var rng = new Random(1); var M = m4x4.Random4x4(-5, +5, rng); // Compare with m4x4 var m = new Matrix(4, 4); for (int v = 0; v != 4; ++v) { for (int c = 0; c != 4; ++c) { m[v, c] = M[v][c]; } } Assert.True(Matrix.FEql(m, M)); Assert.True(Math_.FEql(M.w.x, m[3, 0])); Assert.True(Math_.FEql(M.x.w, m[0, 3])); Assert.True(Math_.FEql(M.z.z, m[2, 2])); Assert.True(Math_.IsInvertible(M)); Assert.True(Matrix.IsInvertible(m)); var M1 = Math_.Invert(M); var m1 = Matrix.Invert(m); Assert.True(Matrix.FEql(m1, M1)); var M2 = Math_.Transpose(M); var m2 = Matrix.Transpose(m); Assert.True(Matrix.FEql(m2, M2)); }
[Test] public void Translation() { var m1 = new m4x4(v4.XAxis, v4.YAxis, v4.ZAxis, new v4(1.0f, 2.0f, 3.0f, 1.0f)); var m2 = m4x4.Translation(new v4(1.0f, 2.0f, 3.0f, 1.0f)); Assert.True(Math_.FEql(m1, m2)); }
[Test] public void Identity() { var m1 = m4x4.Identity; var m2 = m4x4.Identity; var m3 = m1 * m2; Assert.True(Math_.FEql(m3, m4x4.Identity)); }
/// <summary>Compare sizes for approximate equality</summary> public static bool FEql(Rect lhs, Rect rhs) { return (Math_.FEql(lhs.X, rhs.X) && Math_.FEql(lhs.Y, rhs.Y) && Math_.FEql(lhs.Width, rhs.Width) && Math_.FEql(lhs.Height, rhs.Height)); }
public void TestMultiply() { var m1 = new m3x4(new v4(1, 2, 3, 4), new v4(1, 1, 1, 1), new v4(4, 3, 2, 1)); var m2 = new m3x4(new v4(1, 1, 1, 1), new v4(2, 2, 2, 2), new v4(-2, -2, -2, -2)); var m3 = new m3x4(new v4(6, 6, 6, 0), new v4(12, 12, 12, 0), new v4(-12, -12, -12, 0)); var r = m1 * m2; Assert.True(Math_.FEql(r, m3)); }
[Test] public void TestTimeSpan() { const string expr_short = "1428d 21h 33m 9s"; const string expr_long = "1428days 21hrs 33mins 9secs"; { var ts = TimeSpan.FromSeconds(123456789); var s = ts.ToPrettyString(); Assert.Equal(s, expr_short); var TS = TimeSpan_.TryParseExpr(expr_long); Assert.Equal(TS, ts); } { var ts = TimeSpan_.TryParseExpr("1d 12Hrs 1min 100secs 5msec"); var TS = new TimeSpan(1, 12, 1, 100, 5); Assert.Equal(ts, TS); } { var ts = TimeSpan_.TryParseExpr("-2mins") ?? throw new Exception("Invalid timespan expression"); var s1 = ts.ToPrettyString(); var s2 = ts.ToPrettyString(short_format: false, min_unit: TimeSpan_.ETimeUnits.Milliseconds, trailing_zeros: true); var s3 = ts.ToPrettyString(short_format: false, min_unit: TimeSpan_.ETimeUnits.Milliseconds, trailing_zeros: false); Assert.Equal(s1, "-2m 0s"); Assert.Equal(s2, "-2mins 0secs 0msecs"); Assert.Equal(s3, "-2mins"); } { var ts = TimeSpan_.TryParseExpr("0mins") ?? throw new Exception("Invalid timespan expression"); var s1 = ts.ToPrettyString(); Assert.Equal(s1, "0s"); } { var ts = TimeSpan_.TryParseExpr("2ms") ?? throw new Exception("Invalid timespan expression"); var s1 = ts.ToPrettyString(); var s2 = ts.ToPrettyString(min_unit: TimeSpan_.ETimeUnits.Milliseconds); Assert.Equal(s1, "0s"); Assert.Equal(s2, "2ms"); } { var ts = TimeSpan_.TryParseExpr("10y 25w 7d") ?? throw new Exception("Invalid timespan expression"); var s1 = ts.ToPrettyString(trailing_zeros: false); var s2 = ts.ToPrettyString(max_unit: TimeSpan_.ETimeUnits.Years, trailing_zeros: false); Assert.True(Math_.FEql(ts.TotalDays, 10 * 365 + 25 * 7 + 7)); Assert.Equal(s1, "3832d"); Assert.Equal(s2, "10y 26w"); } { var ts = TimeSpan_.TryParseExpr("-10y 25w 7d") ?? throw new Exception("Invalid timespan expression"); var s1 = ts.ToPrettyString(trailing_zeros: false); var s2 = ts.ToPrettyString(max_unit: TimeSpan_.ETimeUnits.Years, trailing_zeros: false); Assert.True(Math_.FEql(ts.TotalDays, -10 * 365 + 25 * 7 + 7)); Assert.Equal(s1, "-3468d"); Assert.Equal(s2, "-9y -26w -1d"); } }
public void DotProduct() { var a = new v8 <Motion>(+1, +2, +3, +4, +5, +6); var b = new v8 <Force>(-1, -2, -3, -4, -5, -6); var pwr0 = Math_.Dot(a, b); var pwr1 = Math_.Dot(b, a); Assert.True(Math_.FEql(pwr0, -91)); Assert.True(Math_.FEql(pwr1, -91)); }
[Test] public void CreateFrom3() { var rng = new Random(123456789); var a2b = m4x4.Transform(v4.Random3N(0.0f, rng), rng.FloatC(0.0f, 1.0f), v4.Random3(0.0f, 10.0f, 1.0f, rng)); var b2a = Math_.Invert(a2b); var a2a = b2a * a2b; Assert.True(Math_.FEql(m4x4.Identity, a2a)); var b2a_fast = Math_.InvertFast(a2b); Assert.True(Math_.FEql(b2a_fast, b2a)); }
[Test] public void CreateFrom() { var rnd = new Random(123456789); var V1 = v4.Random3(0.0f, 10.0f, 1.0f, rnd); var a2b = m4x4.Transform(v4.Random3N(0.0f, rnd), rnd.FloatC(0, (float)Math_.TauBy2), v4.Random3(0.0f, 10.0f, 1.0f, rnd)); var b2c = m4x4.Transform(v4.Random3N(0.0f, rnd), rnd.FloatC(0, (float)Math_.TauBy2), v4.Random3(0.0f, 10.0f, 1.0f, rnd)); Assert.True(Math_.IsOrthonormal(a2b)); Assert.True(Math_.IsOrthonormal(b2c)); var V2 = a2b * V1; var V3 = b2c * V2; var a2c = b2c * a2b; var V4 = a2c * V1; Assert.True(Math_.FEql(V3, V4)); }
[Test] public void CreateFrom2() { var m1 = m4x4.Transform(1.0f, 0.5f, 0.7f, v4.Origin); var m2 = new m4x4(new quat(1.0f, 0.5f, 0.7f), v4.Origin); Assert.True(Math_.IsOrthonormal(m1)); Assert.True(Math_.IsOrthonormal(m2)); Assert.True(Math_.FEql(m1, m2)); var rng = new Random(123456879); var ang = rng.FloatC(0.0f, 1.0f); var axis = v4.Random3N(0.0f, rng); m1 = m4x4.Transform(axis, ang, v4.Origin); m2 = new m4x4(new quat(axis, ang), v4.Origin); Assert.True(Math_.IsOrthonormal(m1)); Assert.True(Math_.IsOrthonormal(m2)); Assert.True(Math_.FEql(m1, m2)); }
[Test] public void TestInversion() { var rng = new Random(); //{ // var m = m2x2.Random(rng, v4.Random3N(0, rng), -(float)Math_.Tau, +(float)Math_.Tau); // var inv_m0 = m3x4.InvertFast(m); // var inv_m1 = m3x4.Invert(m); // Assert.True(m3x4.FEql(inv_m0, inv_m1, 0.001f)); //} { //m2x2.Random(rng, -5.0f, +5.0f); var m = new m2x2( new v2(-3.0f, +4.2f), new v2(1.2f, -0.3f)); var inv_m = Math_.Invert(m); var I0 = inv_m * m; var I1 = m * inv_m; Assert.True(Math_.FEql(I1, m2x2.Identity)); Assert.True(Math_.FEql(I0, m2x2.Identity)); } { var m = new m2x2( new v2(4f, 7f), new v2(2f, 6f)); var inv_m = Math_.Invert(m); var det = 4f * 6f - 7f * 2f; var INV_M = new m2x2( new v2(6f, -7f) / det, new v2(-2f, 4f) / det); Assert.True(Math_.FEql(m * INV_M, m2x2.Identity)); Assert.True(Math_.FEql(inv_m, INV_M)); } }
[Test] public void FromLinearRegression() { { var pts = new v2[] { new v2(0, 15), new v2(1, 13), new v2(2, 10), new v2(3, 7), new v2(4, 4), new v2(5, 1), }; var m = Monic.FromLinearRegression(pts); //Assert.True(Math_.FEql(m.A, 0.689393937587738)); //Assert.True(Math_.FEql(m.B, -6.10151338577271)); } { var pts = new v2[] { new v2(0, 15), new v2(1, 13), new v2(2, 10), new v2(3, 7), new v2(4, 4), new v2(5, 1), new v2(6, 5), new v2(7, 8), new v2(8, 13), new v2(9, 19), }; var q = Quadratic.FromLinearRegression(pts); Assert.True(Math_.FEql((float)q.A, 0.689394f)); Assert.True(Math_.FEql((float)q.B, -6.10151672f)); Assert.True(Math_.FEql((float)q.C, 17.3090973f)); } }
/// <summary>Show the view3D context menu</summary> public void ShowContextMenu() { if (Window == null) { return; } var context_menu = new ContextMenuStrip(); context_menu.Closed += (s, a) => Refresh(); { // View var view_menu = context_menu.Items.Add2(new ToolStripMenuItem("View") { Name = CMenuItems.View }); { // Show focus var opt = view_menu.DropDownItems.Add2(new ToolStripMenuItem("Show Focus") { Name = CMenuItems.ViewMenu.ShowFocus }); opt.Checked = Window.FocusPointVisible; opt.Click += (s, a) => { Window.FocusPointVisible = !Window.FocusPointVisible; Refresh(); }; } { // Show Origin var opt = view_menu.DropDownItems.Add2(new ToolStripMenuItem("Show Origin") { Name = CMenuItems.ViewMenu.ShowOrigin }); opt.Checked = Window.OriginPointVisible; opt.Click += (s, a) => { Window.OriginPointVisible = !Window.OriginPointVisible; Refresh(); }; } { // Show coords } { // Axis Views var opt = view_menu.DropDownItems.Add2(new ToolStripComboBox("Views") { Name = CMenuItems.ViewMenu.Views, DropDownStyle = ComboBoxStyle.DropDownList }); opt.Items.Add("Views"); opt.Items.Add("Axis +X"); opt.Items.Add("Axis -X"); opt.Items.Add("Axis +Y"); opt.Items.Add("Axis -Y"); opt.Items.Add("Axis +Z"); opt.Items.Add("Axis -Z"); opt.Items.Add("Axis -X,-Y,-Z"); opt.SelectedIndex = 0; opt.SelectedIndexChanged += (s, a) => { var pos = Camera.FocusPoint; switch (opt.SelectedIndex) { case 1: Camera.ResetView(v4.XAxis); break; case 2: Camera.ResetView(-v4.XAxis); break; case 3: Camera.ResetView(v4.YAxis); break; case 4: Camera.ResetView(-v4.YAxis); break; case 5: Camera.ResetView(v4.ZAxis); break; case 6: Camera.ResetView(-v4.ZAxis); break; case 7: Camera.ResetView(-v4.XAxis - v4.YAxis - v4.ZAxis); break; } Camera.FocusPoint = pos; Refresh(); }; } { // Object Manager UI //var obj_mgr_ui = new ToolStripMenuItem("Object Manager"); //view_menu.DropDownItems.Add(obj_mgr_ui); //obj_mgr_ui.Click += (s,a) => Window.ShowObjectManager(true); } } { // Navigation var rdr_menu = context_menu.Items.Add2(new ToolStripMenuItem("Navigation") { Name = CMenuItems.Navigation }); { // Reset View var opt = rdr_menu.DropDownItems.Add2(new ToolStripMenuItem("Reset View") { Name = CMenuItems.NavMenu.ResetView }); opt.Click += (s, a) => { Camera.ResetView(); Refresh(); }; } { // Align to var align_menu = rdr_menu.DropDownItems.Add2(new ToolStripMenuItem("Align") { Name = CMenuItems.NavMenu.Align }); { var opt = align_menu.DropDownItems.Add2(new ToolStripComboBox("Aligns") { Name = CMenuItems.NavMenu.AlignMenu.Aligns, DropDownStyle = ComboBoxStyle.DropDownList }); opt.Items.Add("None"); opt.Items.Add("X"); opt.Items.Add("Y"); opt.Items.Add("Z"); var axis = Camera.AlignAxis; if (Math_.FEql(axis, v4.XAxis)) { opt.SelectedIndex = 1; } else if (Math_.FEql(axis, v4.YAxis)) { opt.SelectedIndex = 2; } else if (Math_.FEql(axis, v4.ZAxis)) { opt.SelectedIndex = 3; } else { opt.SelectedIndex = 0; } opt.SelectedIndexChanged += (s, a) => { switch (opt.SelectedIndex) { default: Camera.AlignAxis = v4.Zero; break; case 1: Camera.AlignAxis = v4.XAxis; break; case 2: Camera.AlignAxis = v4.YAxis; break; case 3: Camera.AlignAxis = v4.ZAxis; break; } Refresh(); }; } } { // Motion lock } { // Orbit //var orbit_menu = new ToolStripMenuItem("Orbit"); //rdr_menu.DropDownItems.Add(orbit_menu); //orbit_menu.Click += delegate {}; } } { // Tools var tools_menu = context_menu.Items.Add2(new ToolStripMenuItem("Tools") { Name = CMenuItems.Tools }); { // Measure var opt = tools_menu.DropDownItems.Add2(new ToolStripMenuItem("Measure...") { Name = CMenuItems.ToolsMenu.Measure }); opt.Click += (s, a) => { ShowMeasurementUI = true; }; } { // Angle var opt = tools_menu.DropDownItems.Add2(new ToolStripMenuItem("Angle...") { Name = CMenuItems.ToolsMenu.Angle }); opt.Click += (s, a) => { Window.ShowAngleTool = true; }; } } { // Rendering var rdr_menu = context_menu.Items.Add2(new ToolStripMenuItem("Rendering") { Name = CMenuItems.Rendering }); { // Solid/Wireframe/Solid+Wire var opt = rdr_menu.DropDownItems.Add2(new ToolStripComboBox { Name = CMenuItems.RenderingMenu.FillMode, DropDownStyle = ComboBoxStyle.DropDownList }); opt.Items.AddRange(Enum <View3d.EFillMode> .Names.Cast <object>().ToArray()); opt.SelectedIndex = (int)Window.FillMode; opt.SelectedIndexChanged += (s, a) => { Window.FillMode = (View3d.EFillMode)opt.SelectedIndex; Refresh(); }; } { // Render2D var opt = rdr_menu.DropDownItems.Add2(new ToolStripMenuItem(Window.Camera.Orthographic ? "Perspective" : "Orthographic") { Name = CMenuItems.RenderingMenu.Orthographic }); opt.Click += (s, a) => { var _2d = Window.Camera.Orthographic; Window.Camera.Orthographic = !_2d; opt.Text = _2d ? "Perspective" : "Orthographic"; Refresh(); }; } { // Lighting... var opt = rdr_menu.DropDownItems.Add2(new ToolStripMenuItem("Lighting...") { Name = CMenuItems.RenderingMenu.Lighting }); opt.Click += (s, a) => { Window.ShowLightingDlg(); }; } { // Background colour var bk_colour_menu = rdr_menu.DropDownItems.Add2(new ToolStripMenuItem("Background Colour") { Name = CMenuItems.RenderingMenu.Background }); var opt = bk_colour_menu.DropDownItems.Add2(new ToolStripButton(" ")); opt.AutoToolTip = false; opt.BackColor = Window.BackgroundColour; opt.Click += (s, a) => { var cd = new ColourUI(); if (cd.ShowDialog() == DialogResult.OK) { opt.BackColor = cd.Colour; } }; opt.BackColorChanged += (s, a) => { Window.BackgroundColour = opt.BackColor; Refresh(); }; } } // Allow users to add custom menu options to the context menu // Do this last so that users have the option of removing options they don't want displayed OnCustomiseContextMenu(new CustomContextMenuEventArgs(context_menu)); context_menu.Show(MousePosition); }
/// <summary>Compare sizes for approximate equality</summary> public static bool FEql(Size lhs, Size rhs) { return (Math_.FEql(lhs.Width, rhs.Width) && Math_.FEql(lhs.Height, rhs.Height)); }
/// <summary>Compare sizes for approximate equality</summary> public static bool FEql(Vector lhs, Vector rhs) { return (Math_.FEql(lhs.X, rhs.X) && Math_.FEql(lhs.Y, rhs.Y)); }
/// <summary>Compare sizes for approximate equality</summary> public static bool FEql(Point lhs, Point rhs) { return (Math_.FEql(lhs.X, rhs.X) && Math_.FEql(lhs.Y, rhs.Y)); }