diff options
Diffstat (limited to 'qtsharp/src/examples/samples/quantumfractals.cs')
-rw-r--r-- | qtsharp/src/examples/samples/quantumfractals.cs | 828 |
1 files changed, 828 insertions, 0 deletions
diff --git a/qtsharp/src/examples/samples/quantumfractals.cs b/qtsharp/src/examples/samples/quantumfractals.cs new file mode 100644 index 00000000..56898912 --- /dev/null +++ b/qtsharp/src/examples/samples/quantumfractals.cs @@ -0,0 +1,828 @@ +// quantumfractals.cs - Port of eeqt to Qt# +// Author: Adam Treat <manyoso@yahoo.com> +// (c) 2002 Adam Treat +// Licensed under the terms of the GNU GPL + +namespace Qf { + + using Qt; + using System; + using System.Threading; + + public class FractalViewer : QMainWindow { + + //Menuing + private QMenuBar menubar; + private QPopupMenu filemenu; + private QPopupMenu shapemenu; + private QPopupMenu settingsmenu; + + public static int Main (string[] args) + { + //Initialize and start the main event loop + QApplication app = new QApplication (args); + FractalViewer view = new FractalViewer (); + app.SetMainWidget (view); + view.Show (); + return app.Exec (); + } + + public FractalViewer (): base (null, "main") + { + SetCaption ("Quantum Fractals"); + + //Setup the display + Display display = new Display (this); + SetCentralWidget (display); + + //Setup the filemenu + filemenu = new QPopupMenu (null, "filemenu"); + filemenu.InsertItem ("&Screenshot", display, SLOT ("SlotScreenshot()")); + filemenu.InsertSeparator (); + filemenu.InsertItem ("&Quit", qApp, SLOT ("quit()")); + + //Setup the shapemenu + shapemenu = new QPopupMenu (null, "typemenu"); + shapemenu.InsertItem( "&Tetrahedron", 0); + shapemenu.InsertItem( "&Cube", 1); + shapemenu.InsertItem( "&Octahedron", 2); + shapemenu.InsertItem( "&Icosahedron", 3); + shapemenu.InsertItem( "&Dodecahedron", 4); + shapemenu.InsertItem( "&Double Tetrahedron", 5); + shapemenu.InsertItem( "&Icosidodecahedron", 6); + + //Connect the shapemenu + QObject.Connect (shapemenu, SIGNAL ("activated(int)"), + display, SLOT("SlotShapeMenu(int)")); + + //Setup the settingsmenu + settingsmenu = new QPopupMenu (null, "settingsmenu"); + settingsmenu.InsertItem ("&Alpha", display, SLOT ("SlotSetAlpha()")); + + //Setup the menubar + menubar = new QMenuBar (this, ""); + menubar.InsertItem ("&File", filemenu); + menubar.InsertItem ("&Shape", shapemenu); + menubar.InsertItem ("&Settings", settingsmenu); + } + } + + public class Display: QWidget, IQuantumFractal { + + //Labels + QLabel count; + QLabel shape; + QLabel alpha; + + //Buttons + QPushButton start; + QPushButton stop; + QPushButton reset; + QPushButton gray; + QPushButton intense; + + //Drawable region + QPaintBuffer buffer; + + //Layouts + QVBoxLayout layout; + QHBoxLayout buttons; + QVBoxLayout labels; + + //Engine controller variables + int[] topDensity = new int[0]; + int[] bottomDensity = new int[0]; + int resolution = 400; + int scale = 1; + double centerX = 0; + double centerY = 0; + int i = 0; + bool Grayscale = true; + bool Intense = false; + bool Running = false; + bool WasRunning = false; + + //The engine + QuantumFractals qf; + Thread engine; + + public Display (QWidget parent): base (parent) + { + //Setup the sizes + QSize size = new QSize (resolution, resolution); + parent.SetBaseSize (size); + + //Some nice colors + SetPaletteBackgroundColor (new QColor ("Black")); + SetPaletteForegroundColor (new QColor ("LightBlue")); + + //Setup the buttons + start = new QPushButton ("Start", this); + stop = new QPushButton ("Stop", this); + reset = new QPushButton ("Reset", this); + gray = new QPushButton ("Color", this); + intense = new QPushButton ("Intensity", this); + + //Setup the labels + count = new QLabel (this); + alpha = new QLabel (this); + shape = new QLabel (this); + + //Setup the drawable + buffer = new QPaintBuffer (this); + buffer.SetMinimumSize (size); + + //Create the layouts + layout = new QVBoxLayout (this); + buttons = new QHBoxLayout (layout); + + //Add some buttons + buttons.AddWidget (start); + buttons.AddWidget (stop); + buttons.AddWidget (reset); + buttons.AddWidget (gray); + buttons.AddWidget (intense); + + //Connect the buttons and SlotQuit + QObject.Connect (start, SIGNAL ("clicked()"), + this, SLOT ("SlotStart()")); + QObject.Connect (stop, SIGNAL ("clicked()"), + this, SLOT ("SlotStop()")); + QObject.Connect (reset, SIGNAL ("clicked()"), + this, SLOT ("SlotReset()")); + QObject.Connect (gray, SIGNAL ("clicked()"), + this, SLOT ("SlotGray()")); + QObject.Connect (intense, SIGNAL ("clicked()"), + this, SLOT ("SlotIntense()")); + QObject.Connect (buffer, SIGNAL ("Painted()"), + this, SLOT ("SlotSetLabels()")); + QObject.Connect (qApp, SIGNAL ("lastWindowClosed ()"), + this, SLOT ("SlotQuit ()")); + + //Layout labels + labels = new QVBoxLayout (layout); + labels.AddWidget (count); + labels.AddWidget (shape); + labels.AddWidget (alpha); + + //Layout buffer + layout.AddWidget (buffer, 1); + + //Finally create the data engine + qf = new QuantumFractals (this); + + //Handle resize events + resizeEvent += new ResizeEvent (TouchResize); + } + + //This is where the controller receives data from the engine + public void UpdateData (double[] d) + { + i++; //Keep track of the number of points + + //Set the density arrays to match the resolution + if (resolution * resolution != topDensity.Length) { + topDensity = new int[resolution * resolution]; + bottomDensity = new int[resolution * resolution]; + } + + //setup the sphere + int res = resolution; + int res2 = res / 2; + int x = res / 2 + (int)(res2 * scale * (d[0] - centerX)); + int y = res / 2 + (int)(res2 * scale * (d[1] - centerY)); + double z = d[2]; + + if ((x < res) && (x >= 0) && (y >= 0) && (y < res)) { + + if (z >= 0) + topDensity[y * resolution + x]++; + else + bottomDensity[y * resolution + x]++; + + } + + //Convert the density into a color + int top = topDensity[y * resolution + x]; + //int bot = bottomDensity[y * resolution + x]; + top = Math.Min (top, 255); + //bot = Math.Min (bot, 255); + + //Log color system not working well :( + if (Intense) { + top = (int)(Math.Log (top + 1)); + //bot = (int)(Math.Log (bot + 1)); + } + + int topdepth = RGB (top,top,top); + //int botdepth = RGB (bot,bot,bot); + + //Finally draw the pixel + SetPixel (x, y, topdepth); + //SetPixel (x, y, botdepth); + } + + //Calls the drawable + public void SetPixel (int x, int y, int depth) + { + buffer.PaintPixel (x, y, depth); + } + + //Convert the color into a depth + public int RGB (int r, int g, int b) + { + if (!Grayscale) { + + r = Intensity (r < 128 ? 128 - r : 0); + g = Intensity (128 - Math.Abs (g - 128)); + b = Intensity (b < 128 ? 0 : b - 128); + + } else { + + r = Intensity (r); + g = Intensity (g); + b = Intensity (b); + + } + //Console.WriteLine ("{0} {1} {2}", r,g,b); + return 256 * 256 * r + 256 * g + b; + } + + //This provides more detail + private int Intensity(int val) + { + int ret; + + double bases = 64; + double scale = 256.0 / (256.0 - bases); + ret = (int)(bases + ((double)val) / scale); + + //if gray then black, if color then white + if (val == 0 && Grayscale) + ret = 0; + else if (val == 0) + ret = 255; + return ret; + } + + //Draw the labels + private void SlotSetLabels () + { + count.SetText ("Count: " + i.ToString ()); + shape.SetText ("Shape: " + qf.GetPolytope ()); + alpha.SetText ("Alpha: " + qf.Alpha.ToString ()); + } + + //Start the engine + private void SlotStart () + { + engine = new Thread(new ThreadStart(qf.Start)); + engine.Start (); + Running = true; + } + + //Stop the engine + private void SlotStop () + { + if (engine != null) + if (engine.IsAlive) + engine.Abort (); + Running = false; + } + + //Reset everything + private void SlotReset () + { + SlotStop (); + ResetBuffer (); + SlotStart (); + } + + //Reset the drawable + private void ResetBuffer () + { + i = 0; + SlotSetLabels (); + topDensity = new int[0]; + bottomDensity = new int[0]; + buffer.Reset (); + } + + //Toggles the color scheme + private void SlotGray () + { + Grayscale = !Grayscale; + } + + //Toggles log color scheme + //Not working so well :( + private void SlotIntense () + { + Intense = !Intense; + } + + //Change the platonic shape + private void SlotShapeMenu (int item) + { + WasRunning = Running ? true : false; + + SlotStop (); + ResetBuffer (); + + switch(item) { + + case 0: + qf.SetPolytope (0); + break; + case 1: + qf.SetPolytope (1); + break; + case 2: + qf.SetPolytope (2); + break; + case 3: + qf.SetPolytope (3); + break; + case 4: + qf.SetPolytope (4); + break; + case 5: + qf.SetPolytope (5); + break; + case 6: + qf.SetPolytope (6); + break; + Default: + qf.SetPolytope (0); + break; + } + + if (WasRunning) + SlotStart (); + } + + //Save the drawable as a screenshot + private void SlotScreenshot () + { + WasRunning = Running ? true : false; + + SlotStop (); + string filename = QFileDialog.GetSaveFileName ( + + QDir.HomeDirPath (), "*", this, "save", + "Save Screenshot", "*.png", true + ); + + if (filename != null) + buffer.Save (filename); + + if (WasRunning) + SlotStart (); + } + + //Set the alpha engine variable + private void SlotSetAlpha () + { + WasRunning = Running ? true : false; + + SlotStop (); + qf.Alpha = QInputDialog.GetDouble ( + + "Set Alpha", "Alpha: ", qf.Alpha, 0, 2, 32 + ); + + if (WasRunning) + SlotStart (); + else + SlotSetLabels (); + } + + //Make sure to quit all threads upon exit + private void SlotQuit () + { + SlotStop (); + buffer.Stop (); + } + + //Need to reset the resolution upon resize + private void TouchResize (QResizeEvent e) + { + int height = buffer.Size ().Height (); + int width = buffer.Size ().Width (); + + resolution = height > width ? width : height; + } + } + + [DeclareQtSignal ("Painted()")] + public class QPaintBuffer : QFrame { + + //Drawables + private QPixmap buffer; + private QImage image; + + //Timer + private TimerCallback call; + private Timer timer; + + public QPaintBuffer (QWidget parent) : base (parent) + { + SetBackgroundMode (Qt.BackgroundMode.NoBackground); + + //Create drawables + buffer = new QPixmap (); + image = new QImage (Size (), 32); + + //Setup the event handlers + paintEvent += new PaintEvent (TouchPaint); + resizeEvent += new ResizeEvent (TouchResize); + focusInEvent += new FocusInEvent (TouchFocus); + focusOutEvent += new FocusOutEvent (TouchFocus); + + //Start the timer + call = new TimerCallback(PaintImage); + timer = new Timer(call, null, 1000, 1000); + + } + + //Resets the drawables + public void Reset () + { + buffer = new QPixmap (); + image = new QImage (Size (), 32); + PaintImage (null); + } + + //Paints a pixel to the image + public void PaintPixel (int x, int y, int depth) + { + lock (this) { + if (x < image.Width () && y < image.Height ()) + image.SetPixel (x, y, (uint)depth); + } + } + + //Saves the image to a file + public void Save (string filename) + { + image.Save (filename, "PNG"); + } + + //Paints the image to the screen and emits Painted + private void PaintImage (object state) + { + buffer.ConvertFromImage (image); + PerformPaint (); + Emit ("Painted()"); + } + + //The actual bitblt to the screen + private void PerformPaint () + { + BitBlt(this, 0, 0, buffer, + 0, 0, -1, -1, RasterOp.CopyROP, false); + } + + //Receive focus events + private void TouchFocus (QFocusEvent e) + { + PerformPaint (); + } + + //Receive paint events + private void TouchPaint (QPaintEvent e) + { + PerformPaint (); + } + + //Receive resize events + private void TouchResize (QResizeEvent e) + { + image = new QImage (e.Size (), 32); + buffer.Resize (e.Size()); + buffer.Fill (new QColor("black")); + BitBlt (buffer, 0, 0, new QPixmap (buffer), + 0, 0, -1, -1, RasterOp.CopyROP, false); + } + + //Dispose of the timer + public void Stop () + { + timer.Dispose (); + } + } + + public interface IQuantumFractal { + + void UpdateData (Double [] data); + } + + //Polytope types + public enum Shapes { + TETRAHEDRON = 0, + CUBE = 1, + OCTAHEDRON = 2, + ICOSAHEDRON = 3, + DODECAHEDRON = 4, + DOUBLE_TETRAHEDRON = 5, + ICOSIDODECAHEDRON = 6 + } + + public class QuantumFractals { + + private int t = 0; + private double[] p; //Detector probabilities + private double[] fp; //Fractal point + private double[][] n; //Detector points + private double[] counter; //Detect counter + private double alpha = 0.61803398874989288039384209090709; //Initialize to 1/phi + + private Random random; + private Shapes polytope; + private IQuantumFractal consumer; + + public QuantumFractals (IQuantumFractal consumer) + { + this.consumer = consumer; + SetPolytope (0); + Init (); + } + + public double Alpha + { + get { return alpha; } + set { alpha = value; } + } + + private void Init () + { + random = new Random (); + + //Default values + t = 0; + + counter = new double[n.Length]; //Detect counter + fp = new double[3]; //Fractal point + p = new double[n.Length]; + + //Initial state + fp[0] = random.NextDouble () -0.5; + fp[1] = random.NextDouble () -0.5; + fp[2] = random.NextDouble () -0.5; + + double sum = Math.Sqrt (Product (fp, fp)); + + fp[0] = fp[0] / sum; + fp[1] = fp[1] / sum; + fp[2] = fp[2] / sum; + } + + //Main fractal generator loop + public void Start () + { + Init (); + + //double n1 = (1.0) / n.Length as double; + double n1 = (1.0) / n.Length; + + double alpha12 = 2 * alpha / (n.Length * (1 + alpha * alpha)); + + do { + //Increase t + t++; + + //Calculate detector click probabilities + for (int i = 0; i < p.Length; i++) + p[i] = n1 + alpha12 * Product (n[i], fp); + + //Get next random number + double r = random.NextDouble (); + + //Check which detector that clicked + double ptmp = 0; + double[] detector = null; + + for (int i = 0; i < p.Length; i++) { + + ptmp += p[i]; + + if (r <= ptmp) { + //We found which detector clicked + detector = n[i]; + counter[i]++; + break; + } + } + + if (detector == null) + detector = n[p.Length - 1]; + + //Project + double sc = Product (fp, detector); + + for (int j = 0; j < 3; j++) + fp[j]= (1 - alpha * alpha) * fp[j] + 2 * alpha * (1 + alpha * sc) * detector[j]; + + //Normalize + double norm = Math.Sqrt (Product (fp, fp)); + + for (int j=0; j<3; j++) + fp[j] /= norm; + + consumer.UpdateData (fp); + + } while (true); + } + + + //Calculate the scalar product of two vectors + private double Product (double[] v1, double[] v2) + { + double sc = 0; + for(int i=0; i < v1.Length; i++) + sc += v1[i] * v2[i]; + return sc; + } + + public string GetPolytope () + { + string ret = String.Empty; + switch (polytope) { + case Shapes.TETRAHEDRON: + ret = "Tetrahedron"; + break; + case Shapes.CUBE: + ret = "Cube"; + break; + case Shapes.OCTAHEDRON: + ret = "Octahedron"; + break; + case Shapes.ICOSAHEDRON: + ret = "Icosahedron"; + break; + case Shapes.DODECAHEDRON: + ret = "Dodecahedron"; + break; + case Shapes.DOUBLE_TETRAHEDRON: + ret = "Double Tetrahedron"; + break; + case Shapes.ICOSIDODECAHEDRON: + ret = "Icosidodecahedron"; + break; + Default: + ret = "Unknown"; + break; + } + return ret; + } + + public void SetPolytope (int type) + { + polytope = (Qf.Shapes)type; + + switch (type) { + + case 0: { + + n = new double[4][]; + n[0] = new double[] {0,0,1.0}; + n[1] = new double[] {0.9428090415820634,0,-0.3333333333333333}; + n[2] = new double[] {-0.4714045207910317,0.816496580927726,-0.3333333333333333}; + n[3] = new double[] {-0.4714045207910317, -0.816496580927726, -0.3333333333333333}; + + break; + } + + case 1: { + + n = new double[8][]; + n[0] = new double[] {0, 0, 1.0}; + n[1] = new double[] {0.9428090415820634, 0, 0.3333333333333333}; + n[2] = new double[] {-0.4714045207910317, 0.816496580927726, 0.3333333333333333}; + n[3] = new double[] {-0.4714045207910317, -0.816496580927726, 0.3333333333333333}; + n[4] = new double[] {0.4714045207910317, 0.816496580927726, -0.3333333333333333}; + n[5] = new double[] {0.4714045207910317, -0.816496580927726, -0.3333333333333333}; + n[6] = new double[] {-0.9428090415820634, 0, -0.3333333333333333}; + n[7] = new double[] {0, 0, -1.0}; + break; + } + + case 2: { + + n = new double[6][]; + n[0] = new double[] {0, 0, 1.0}; + n[1] = new double[] {1.0, 0, 0}; + n[2] = new double[] {0, 1.0, 0}; + n[3] = new double[] {-1.0, 0, 0}; + n[4] = new double[] {0, -1.0, 0}; + n[5] = new double[] {0, 0, -1.0}; + + break; + } + + case 3: { + + n = new double[12][]; + n[0] = new double[] {0, 0, 1.0}; + n[1] = new double[] {0.8944271909999159, 0, 0.4472135954999579}; + n[2] = new double[] {0.276393202250021, 0.85065080835204, 0.4472135954999579}; + n[3] = new double[] {-0.723606797749979, 0.5257311121191336, 0.4472135954999579}; + n[4] = new double[] {-0.723606797749979, -0.5257311121191336, 0.4472135954999579}; + n[5] = new double[] {0.276393202250021, -0.85065080835204, 0.4472135954999579}; + n[6] = new double[] {0.723606797749979, 0.5257311121191336, -0.4472135954999579}; + n[7] = new double[] {0.723606797749979, -0.5257311121191336, -0.4472135954999579}; + n[8] = new double[] {-0.276393202250021, 0.85065080835204, -0.4472135954999579}; + n[9] = new double[] {-0.8944271909999159, 0, -0.4472135954999579}; + n[10] = new double[] {-0.276393202250021, -0.85065080835204, -0.4472135954999579}; + n[11] = new double[] {0, 0, -1.0}; + + break; + } + + case 4: { + + n = new double[20][]; + n[0] = new double[] {0, 0, 1.0}; + n[1] = new double[] {0.6666666666666666, 0, 0.7453559924999299}; + n[2] = new double[] {-0.3333333333333333, 0.5773502691896257, 0.7453559924999299}; + n[3] = new double[] {-0.3333333333333333, -0.5773502691896257, 0.7453559924999299}; + n[4] = new double[] {0.7453559924999299, 0.5773502691896257, 0.3333333333333333}; + n[5] = new double[] {0.7453559924999299, -0.5773502691896257, 0.3333333333333333}; + n[6] = new double[] {-0.8726779962499649, 0.35682208977308993, 0.3333333333333333}; + n[7] = new double[] {0.12732200375003502, 0.9341723589627157, 0.3333333333333333}; + n[8] = new double[] {0.12732200375003502, -0.9341723589627157, 0.3333333333333333}; + n[9] = new double[] {-0.8726779962499649, -0.35682208977308993, 0.3333333333333333}; + n[10] = new double[] {0.8726779962499649, 0.35682208977308993, -0.3333333333333333}; + n[11] = new double[] {0.8726779962499649, -0.35682208977308993, -0.3333333333333333}; + n[12] = new double[] {-0.7453559924999299, 0.5773502691896257, -0.3333333333333333}; + n[13] = new double[] {-0.12732200375003502, 0.9341723589627157, -0.3333333333333333}; + n[14] = new double[] {-0.12732200375003502, -0.9341723589627157, -0.3333333333333333}; + n[15] = new double[] {-0.7453559924999299, -0.5773502691896257, -0.3333333333333333}; + n[16] = new double[] {0.3333333333333333, 0.5773502691896257, -0.7453559924999299}; + n[17] = new double[] {0.3333333333333333, -0.5773502691896257, -0.7453559924999299}; + n[18] = new double[] {-0.6666666666666666, 0, -0.7453559924999299}; + n[19] = new double[] {0, 0, -1.0}; + break; + } + + case 5: { + + n = new double[8][]; + n[0] = new double[] {0,0,1.0}; + n[1] = new double[] {0.9428090415820634,0,-0.3333333333333333}; + n[2] = new double[] {-0.4714045207910317,0.816496580927726,-0.3333333333333333}; + n[3] = new double[] {-0.4714045207910317, -0.816496580927726, -0.3333333333333333}; + n[4] = new double[] {0,0,-1.0}; + n[5] = new double[] {-0.9428090415820634,0,0.3333333333333333}; + n[6] = new double[] {0.4714045207910317,-0.816496580927726,0.3333333333333333}; + n[7] = new double[] {0.4714045207910317, 0.816496580927726, 0.3333333333333333}; + + break; + } + + case 6: { + + double u=0.5; + double v=0.8090169943749475; // (1/2)*phi + double w=0.3090169943749474; // (1/2)/phi + + n = new double[30][]; + n[0] = new double[] {1,0,0}; + n[1] = new double[] {-1,0,0}; + n[2] = new double[] {0,1,0}; + n[3] = new double[] {0,-1,0}; + n[4] = new double[] {0,0,1}; + n[5] = new double[] {0,0,-1}; + n[6] = new double[] {u,v,w}; + n[7] = new double[] {-u,v,w}; + n[8] = new double[] {u,-v,w}; + n[9] = new double[] {u,v,-w}; + n[10] = new double[] {-u,-v,w}; + n[11] = new double[] {u,-v,-w}; + n[12] = new double[] {-u,v,-w}; + n[13] = new double[] {-u,-v,-w}; + n[14] = new double[] {v,w,u}; + n[15] = new double[] {v,w,-u}; + n[16] = new double[] {-v,w,u}; + n[17] = new double[] {v,-w,u}; + n[18] = new double[] {-v,w,-u}; + n[19] = new double[] {-v,-w,u}; + n[20] = new double[] {v,-w,-u}; + n[21] = new double[] {-v,-w,-u}; + n[22] = new double[] {w,u,v}; + n[23] = new double[] {w,-u,v}; + n[24] = new double[] {w,u,-v}; + n[25] = new double[] {-w,u,v}; + n[26] = new double[] {w,-u,-v}; + n[27] = new double[] {-w,u,-v}; + n[28] = new double[] {-w,-u,v}; + n[29] = new double[] {-w,-u,-v}; + break; + } + + Default: + break; + } + } + } +} |