diff --git a/Tetrahedrons/MVec3d.cs b/Tetrahedrons/MVec3d.cs
new file mode 100644
index 0000000..7e60e19
--- /dev/null
+++ b/Tetrahedrons/MVec3d.cs
@@ -0,0 +1,204 @@
+using System;
+using OpenTK;
+
+namespace Tetrahedrons
+{
+ // ReSharper disable once InconsistentNaming
+ public struct MVec3d
+ {
+ public static readonly MVec3d Unit = new MVec3d(1, 0, 0, 0, 0, 0, 0, 0);
+ public static readonly MVec3d Unit1 = new MVec3d(0, 1, 0, 0, 0, 0, 0, 0);
+ public static readonly MVec3d Unit2 = new MVec3d(0, 0, 1, 0, 0, 0, 0, 0);
+ public static readonly MVec3d Unit3 = new MVec3d(0, 0, 0, 1, 0, 0, 0, 0);
+ public static readonly MVec3d Unit23 = new MVec3d(0, 0, 0, 0, 1, 0, 0, 0);
+ public static readonly MVec3d Unit31 = new MVec3d(0, 0, 0, 0, 0, 1, 0, 0);
+ public static readonly MVec3d Unit12 = new MVec3d(0, 0, 0, 0, 0, 0, 1, 0);
+ public static readonly MVec3d Unit123 = new MVec3d(0, 0, 0, 0, 0, 0, 0, 1);
+
+ public double E;
+ public double E1;
+ public double E2;
+ public double E3;
+ public double E23;
+ public double E31;
+ public double E12;
+ public double E123;
+
+ public MVec3d(double e, double e1, double e2, double e3, double e23, double e31, double e12, double e123)
+ {
+ E = e;
+ E1 = e1;
+ E2 = e2;
+ E3 = e3;
+ E23 = e23;
+ E31 = e31;
+ E12 = e12;
+ E123 = e123;
+ }
+
+ public MVec3d(MVec3d s, MVec3d v, MVec3d b, MVec3d t)
+ : this(s.E, v.E1, v.E2, v.E3, b.E23, b.E31, b.E12, t.E123)
+ {
+ }
+
+ public static MVec3d Scalar(double e)
+ {
+ return new MVec3d(e, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ public static MVec3d Vector(double e1, double e2, double e3)
+ {
+ return new MVec3d(0, e1, e2, e3, 0, 0, 0, 0);
+ }
+
+ public static MVec3d Vector(Vector3d v)
+ {
+ return new MVec3d(0, v.X, v.Y, v.Z, 0, 0, 0, 0);
+ }
+
+ public static MVec3d Bivector(double e23, double e31, double e12)
+ {
+ return new MVec3d(0, 0, 0, 0, e23, e31, e12, 0);
+ }
+
+ public static MVec3d Trivector(double e123)
+ {
+ return new MVec3d(0, 0, 0, 0, 0, 0, 0, e123);
+ }
+
+ public static MVec3d Complex(double real, double imag)
+ {
+ return new MVec3d(real, 0, 0, 0, 0, 0, 0, imag);
+ }
+
+ public static MVec3d Complex(double w, double i, double j, double k)
+ {
+ return new MVec3d(w, 0, 0, 0, i, j, k, 0);
+ }
+
+ public static MVec3d Complex(double angle, MVec3d plane)
+ {
+ return Math.Cos(angle) + Math.Sin(angle) * plane;
+ }
+
+ public static MVec3d Add(MVec3d m, MVec3d n)
+ {
+ return new MVec3d(m.E + n.E,
+ m.E1 + n.E1, m.E2 + n.E2, m.E3 + n.E3,
+ m.E23 + n.E23, m.E31 + n.E31, m.E12 + n.E12,
+ m.E123 + n.E123);
+ }
+
+ public static MVec3d Sub(MVec3d m, MVec3d n)
+ {
+ return new MVec3d(m.E - n.E,
+ m.E1 - n.E1, m.E2 - n.E2, m.E3 - n.E3,
+ m.E23 - n.E23, m.E31 - n.E31, m.E12 - n.E12,
+ m.E123 - n.E123);
+ }
+
+ public static MVec3d Mult(MVec3d m, MVec3d n)
+ {
+ return new MVec3d(
+ m.E * n.E + m.E1 * n.E1 + m.E2 * n.E2 + m.E3 * n.E3 - m.E23 * n.E23 - m.E31 * n.E31 - m.E12 * n.E12 - m.E123 * n.E123,
+ m.E * n.E1 + m.E1 * n.E - m.E2 * n.E12 + m.E3 * n.E31 - m.E23 * n.E123 - m.E31 * n.E3 + m.E12 * n.E2 - m.E123 * n.E23,
+ m.E * n.E2 + m.E1 * n.E12 + m.E2 * n.E - m.E3 * n.E23 + m.E23 * n.E3 - m.E31 * n.E123 - m.E12 * n.E1 - m.E123 * n.E31,
+ m.E * n.E3 - m.E1 * n.E31 + m.E2 * n.E23 + m.E3 * n.E - m.E23 * n.E2 + m.E31 * n.E1 - m.E12 * n.E123 - m.E123 * n.E12,
+ m.E * n.E23 + m.E1 * n.E123 + m.E2 * n.E3 - m.E3 * n.E2 + m.E23 * n.E - m.E31 * n.E12 + m.E12 * n.E31 + m.E123 * n.E1,
+ m.E * n.E31 - m.E1 * n.E3 + m.E2 * n.E123 + m.E3 * n.E1 + m.E23 * n.E12 + m.E31 * n.E - m.E12 * n.E23 + m.E123 * n.E2,
+ m.E * n.E12 + m.E1 * n.E2 - m.E2 * n.E1 + m.E3 * n.E123 - m.E23 * n.E31 + m.E31 * n.E23 + m.E12 * n.E + m.E123 * n.E3,
+ m.E * n.E123 + m.E1 * n.E23 + m.E2 * n.E31 + m.E3 * n.E12 + m.E23 * n.E1 + m.E31 * n.E2 + m.E12 * n.E3 + m.E123 * n.E
+ );
+ }
+
+ public double Norm2 => E * E + E1 * E1 + E2 * E2 + E3 * E3 + E23 * E23 + E31 * E31 + E12 * E12 + E123 * E123;
+ public double Norm => Math.Sqrt(Norm2);
+
+ public MVec3d Inv
+ {
+ get
+ {
+ var n2 = Norm2;
+ return new MVec3d(E / n2, -E1 / n2, -E2 / n2, -E3 / n2, -E23 / n2, -E31 / n2, -E12 / n2, E123 / n2);
+// return new MVec3d(E / n2, E1 / n2, E2 / n2, E3 / n2, E23 / n2, E31 / n2, E12 / n2, E123 / n2);
+ }
+ }
+
+ public MVec3d Grade(int k)
+ {
+ switch (k)
+ {
+ case 0:
+ return Scalar(E);
+ case 1:
+ return Vector(E1, E2, E3);
+ case 2:
+ return Bivector(E23, E31, E12);
+ case 3:
+ return Trivector(E123);
+ default:
+ return new MVec3d();
+ }
+ }
+
+ public static MVec3d Inner(MVec3d m, MVec3d n)
+ {
+ var m0 = m.Grade(0);
+ var m1 = m.Grade(1);
+ var m2 = m.Grade(2);
+ var m3 = m.Grade(3);
+
+ var n0 = n.Grade(0);
+ var n1 = n.Grade(1);
+ var n2 = n.Grade(2);
+ var n3 = n.Grade(3);
+
+ return new MVec3d(
+ m0 * n0 + m1 * n1 + m2 * n2 + m3 * n3,
+ m0 * n1 + m1 * n2 + m2 * n3,
+ m0 * n2 + m1 * n3,
+ m0 * n3
+ );
+ }
+
+ public static MVec3d Outer(MVec3d m, MVec3d n)
+ {
+ var m0 = m.Grade(0);
+ var m1 = m.Grade(1);
+ var m2 = m.Grade(2);
+ var m3 = m.Grade(3);
+
+ var n0 = n.Grade(0);
+ var n1 = n.Grade(1);
+ var n2 = n.Grade(2);
+ var n3 = n.Grade(3);
+
+ return new MVec3d(
+ m0 * n0,
+ m1 * n0 + m0 * n1,
+ m2 * n0 + m1 * n1 + m0 * n2,
+ m3 * n0 + m2 * n1 + m1 * n2 + m0 * m3
+ );
+ }
+
+ public static MVec3d operator ~(MVec3d m) => m.Inv;
+ public static MVec3d operator *(MVec3d m, MVec3d n) => Mult(m, n);
+
+ public static MVec3d operator +(MVec3d m, MVec3d n) => Add(m, n);
+ public static MVec3d operator -(MVec3d m, MVec3d n) => Sub(m, n);
+
+ public static MVec3d operator &(MVec3d m, MVec3d n) => Inner(m, n);
+ public static MVec3d operator ^(MVec3d m, MVec3d n) => Outer(m, n);
+
+ public Vector3d VectorPart => new Vector3d(E1, E2, E3);
+
+ public static implicit operator MVec3d(Vector3 v) => new MVec3d(0, v.X, v.Y, v.Z, 0, 0, 0, 0);
+ public static implicit operator MVec3d(Vector3d v) => new MVec3d(0, v.X, v.Y, v.Z, 0, 0, 0, 0);
+ public static implicit operator MVec3d(double s) => new MVec3d(s, 0, 0, 0, 0, 0, 0, 0);
+
+ public override string ToString()
+ {
+ return $"({E:0.00} {E1:0.00}e1 {E2:0.00}e2 {E3:0.00}e3 {E23:0.00}e23 {E31:0.00}e31 {E12:0.00}e12 {E123:0.00}e123)";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tetrahedrons/OpenTK.dll.config b/Tetrahedrons/OpenTK.dll.config
new file mode 100644
index 0000000..7098d39
--- /dev/null
+++ b/Tetrahedrons/OpenTK.dll.config
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tetrahedrons/Program.cs b/Tetrahedrons/Program.cs
index 8eb5155..6175764 100644
--- a/Tetrahedrons/Program.cs
+++ b/Tetrahedrons/Program.cs
@@ -1,9 +1,13 @@
-namespace Tetrahedrons
+using OpenTK;
+
+namespace Tetrahedrons
{
- internal class Program
+ internal class Program : GameWindow
{
public static void Main(string[] args)
{
+ using(var p = new TetrahedronWindow())
+ p.Run();
}
}
}
\ No newline at end of file
diff --git a/Tetrahedrons/TetrahedronWindow.cs b/Tetrahedrons/TetrahedronWindow.cs
new file mode 100644
index 0000000..8f02e7d
--- /dev/null
+++ b/Tetrahedrons/TetrahedronWindow.cs
@@ -0,0 +1,293 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Net.Mail;
+using System.Security;
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using OpenTK.Input;
+
+namespace Tetrahedrons
+{
+ public struct Polygon
+ {
+ public Vector3d[] Points;
+ public Color Color;
+
+ public Polygon(Vector3d[] points) : this(points, Color.DodgerBlue)
+ {
+ }
+
+ public Polygon(Vector3d[] points, Color color)
+ {
+ Points = points;
+ Color = color;
+ }
+
+ public void Draw()
+ {
+ GL.Begin(PrimitiveType.TriangleStrip);
+ GL.Color3(Color);
+ foreach (var v in Points)
+ GL.Vertex3(v);
+ GL.End();
+ }
+
+ public static Polygon operator +(Polygon p, MVec3d m)
+ {
+ var pts = new Vector3d[p.Points.Length];
+ for (var i = 0; i < p.Points.Length; i++)
+ pts[i] = (p.Points[i] + m).VectorPart;
+ return new Polygon(pts, p.Color);
+ }
+
+ public static Polygon operator -(Polygon p, MVec3d m)
+ {
+ var pts = new Vector3d[p.Points.Length];
+ for (var i = 0; i < p.Points.Length; i++)
+ pts[i] = (p.Points[i] - m).VectorPart;
+ return new Polygon(pts, p.Color);
+ }
+
+ public static Polygon operator *(Polygon p, MVec3d m)
+ {
+ var pts = new Vector3d[p.Points.Length];
+ for (var i = 0; i < p.Points.Length; i++)
+ pts[i] = (p.Points[i] * m).VectorPart;
+ return new Polygon(pts, p.Color);
+ }
+
+ public static Polygon operator ^(Polygon p, MVec3d m)
+ {
+ var pts = new Vector3d[p.Points.Length];
+ for (var i = 0; i < p.Points.Length; i++)
+ pts[i] = (p.Points[i] ^ m).VectorPart;
+ return new Polygon(pts, p.Color);
+ }
+
+ public static Polygon operator &(Polygon p, MVec3d m)
+ {
+ var pts = new Vector3d[p.Points.Length];
+ for (var i = 0; i < p.Points.Length; i++)
+ pts[i] = (p.Points[i] & m).VectorPart;
+ return new Polygon(pts, p.Color);
+ }
+ }
+
+ public class Tetrahedron
+ {
+ public readonly Vector3d[] Points;
+ public Color Color;
+ public Color WireColor;
+
+ public Tetrahedron(Vector3d p1, Vector3d p2, Vector3d p3, Vector3d p4) : this(p1, p2, p3, p4, Color.GhostWhite)
+ {
+ }
+
+ public Tetrahedron(Vector3d p1, Vector3d p2, Vector3d p3, Vector3d p4, Color color) : this(p1, p2, p3, p4, color, Color.Maroon)
+ {
+ }
+
+ public Tetrahedron(Vector3d p1, Vector3d p2, Vector3d p3, Vector3d p4, Color color, Color wireColor)
+ {
+ Color = color;
+ WireColor = wireColor;
+ Points = new[] {p1, p2, p3, p4};
+ }
+
+ public void Draw(bool wire = true)
+ {
+ if (wire)
+ {
+ GL.Begin(PrimitiveType.Lines);
+ GL.Color3(WireColor);
+
+ for (var i = 0; i < 4; i++)
+ for (var j = i + 1; j < 4; j++)
+ {
+ GL.Vertex3(Points[i]);
+ GL.Vertex3(Points[j]);
+ }
+
+ GL.End();
+ }
+ else
+ {
+ GL.Begin(PrimitiveType.Triangles);
+ GL.Color3(Color);
+
+ for (var i = 0; i < 4; i++)
+ for (var j = i + 1; j < 4; j++)
+ for (var k = j + 1; k < 4; k++)
+ {
+ GL.Vertex3(Points[i]);
+ GL.Vertex3(Points[j]);
+ GL.Vertex3(Points[k]);
+ }
+
+ GL.End();
+ }
+ }
+
+ public Polygon Intersection(MVec3d blade, Vector3d pivot)
+ {
+ var pts = new Vector3d[4];
+ for (var i = 0; i < 4; i++)
+ {
+ pts[i] = Points[i] - pivot;
+ }
+
+ var a = blade * MVec3d.Unit123;
+ var sides = new double[4];
+ for (var i = 0; i < 4; i++)
+ {
+ sides[i] = (a & ((pts[i] ^ blade) * ~blade)).E; // normal dot rejection
+ }
+
+ var vecs = new List(4);
+
+ for (var i = 0; i < 4; i++)
+ {
+ for (var j = i + 1; j < 4; j++)
+ {
+ if (sides[i] * sides[j] >= 0) continue; // both pts on same side
+
+ var t = ((blade ^ pts[i]) * ~(blade ^ (pts[j] - pts[i]))).E;
+ var point = pts[i] + t * (pts[j] - pts[i]);
+ vecs.Add(point + pivot);
+ }
+ }
+
+ return new Polygon(vecs.ToArray());
+ }
+ }
+
+ public class TetrahedronWindow : GameWindow
+ {
+ private Matrix4 _proj;
+ private Matrix4 _view;
+
+ private double _t;
+ private bool _pause;
+ private bool _div;
+ private Tetrahedron _tetra;
+ private Polygon _polyg;
+
+ private Polygon _square = new Polygon(new[] {new Vector3d(-1, -1, 0), new Vector3d(-1, 1, 0), new Vector3d(1, -1, 0), new Vector3d(1, 1, 0),}, Color.Red);
+
+ protected override void OnLoad(EventArgs e)
+ {
+ base.OnLoad(e);
+
+ X = (DisplayDevice.Default.Width - Width) / 2;
+ Y = (DisplayDevice.Default.Height - Height) / 2;
+
+ _tetra = new Tetrahedron(new Vector3d(1, 1, 1), new Vector3d(-1, -1, 1), new Vector3d(-1, 1, -1), new Vector3d(1, -1, -1));
+ _polyg = new Polygon(new[] {new Vector3d(-1, -1, 0), new Vector3d(-1, 1, 0), new Vector3d(1, -1, 0), new Vector3d(1, 1, 0)});
+
+ _view = Matrix4.LookAt(Vector3.Zero, -new Vector3(1, .6f, 1f), Vector3.UnitZ);
+ }
+
+ protected override void OnRenderFrame(FrameEventArgs e)
+ {
+ base.OnRenderFrame(e);
+
+ GL.Viewport(ClientRectangle);
+
+ GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+ GL.PointSize(10f);
+
+// _view = Matrix4.LookAt(Vector3.Zero, new Vector3((float) Math.Cos(_t / 5), (float) Math.Sin(_t / 5), -1), Vector3.UnitZ);
+
+ GL.PushMatrix();
+ GL.MatrixMode(MatrixMode.Projection);
+ GL.LoadMatrix(ref _proj);
+ GL.MatrixMode(MatrixMode.Modelview);
+ GL.LoadMatrix(ref _view);
+
+ GL.Enable(EnableCap.DepthTest);
+ _tetra.Draw(wire: false);
+ GL.Disable(EnableCap.DepthTest);
+ if (_div)
+ {
+ GL.PushMatrix();
+ GL.MatrixMode(MatrixMode.Modelview);
+ GL.LoadMatrix(ref Matrix4d.Identity);
+ _square.Draw();
+ _polyg.Draw();
+ GL.PopMatrix();
+ }
+ else
+ _polyg.Draw();
+
+ GL.Enable(EnableCap.DepthTest);
+ _tetra.Draw(wire: true);
+
+ GL.PopMatrix();
+
+ SwapBuffers();
+ }
+
+ protected override void OnUpdateFrame(FrameEventArgs e)
+ {
+ base.OnUpdateFrame(e);
+ _proj = Matrix4.CreateOrthographic(6, 6f * Height / Width, -2, 2);
+ _t += e.Time;
+
+ if (_pause)
+ return;
+
+// var b1 = MVec3d.Unit2;
+// var b2 = MVec3d.Unit3;
+// var pivot = new Vector3d(Math.Cos(_t), 0, 0);
+
+ var b1 = MVec3d.Vector(0, Math.Cos(_t * .2), Math.Sin(_t * .5));
+ var b2 = MVec3d.Vector(Math.Cos(_t * .6), 0, Math.Sin(_t * .4));
+ var pivot = Vector3d.Zero;
+
+// var b1 = MVec3d.Vector(Math.Cos(_t/2), Math.Sin(_t/2), 0);
+// var b2 = MVec3d.Unit3;
+// var pivot = Vector3d.Zero;
+
+ var blade = MVec3d.Outer(b1, b2);
+
+// var rot = MVec3d.Complex(_t / 2, MVec3d.Unit12);
+// var b1 = rot * MVec3d.Unit2 * ~rot;
+// var b2 = rot * MVec3d.Unit3 * ~rot;
+// var pln = MVec3d.Outer(b1, b2);
+// var blade = pln;
+// var pivot = Vector3d.Zero;
+
+ Console.Out.WriteLine("b1 = {0}", b1);
+ Console.Out.WriteLine("b2 = {0}", b2);
+
+ _polyg = _tetra.Intersection(blade, pivot);
+
+ if (_div)
+ {
+ for (var i = 0; i < _polyg.Points.Length; i++)
+ {
+ MVec3d p = _polyg.Points[i];
+ var x = ((p & b1) * ~b1) & b1;
+ var y = ((p ^ b1) * ~b1) & ((b2 ^ b1) * ~b1);
+ _polyg.Points[i] = new Vector3d(x.E, y.E, 0);
+ }
+ }
+ }
+
+ protected override void OnKeyDown(KeyboardKeyEventArgs e)
+ {
+ base.OnKeyDown(e);
+
+ switch (e.Key)
+ {
+ case Key.Space:
+ _pause = !_pause;
+ break;
+ case Key.A:
+ _div = !_div;
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tetrahedrons/Tetrahedrons.csproj b/Tetrahedrons/Tetrahedrons.csproj
index eb7b4e3..a76912a 100644
--- a/Tetrahedrons/Tetrahedrons.csproj
+++ b/Tetrahedrons/Tetrahedrons.csproj
@@ -1,54 +1,62 @@
-
-
- Debug
- AnyCPU
- {D70DFA78-49B4-404B-BE1C-7CDC0DAE26FD}
- Exe
- Properties
- Tetrahedrons
- Tetrahedrons
- v4.0
- 512
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Tetrahedrons/packages.config b/Tetrahedrons/packages.config
new file mode 100644
index 0000000..b2e9742
--- /dev/null
+++ b/Tetrahedrons/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file