You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebindings/qtsharp/src/examples/samples/quantumfractals.cs

829 lines
21 KiB

// 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 : TQMainWindow {
//Menuing
private TQMenuBar menubar;
private TQPopupMenu filemenu;
private TQPopupMenu shapemenu;
private TQPopupMenu settingsmenu;
public static int Main (string[] args)
{
//Initialize and start the main event loop
TQApplication app = new TQApplication (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 TQPopupMenu (null, "filemenu");
filemenu.InsertItem ("&Screenshot", display, TQ_SLOT ("SlotScreenshot()"));
filemenu.InsertSeparator ();
filemenu.InsertItem ("&Quit", tqApp, TQ_SLOT ("quit()"));
//Setup the shapemenu
shapemenu = new TQPopupMenu (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
TQObject.Connect (shapemenu, TQ_SIGNAL ("activated(int)"),
display, TQ_SLOT("SlotShapeMenu(int)"));
//Setup the settingsmenu
settingsmenu = new TQPopupMenu (null, "settingsmenu");
settingsmenu.InsertItem ("&Alpha", display, TQ_SLOT ("SlotSetAlpha()"));
//Setup the menubar
menubar = new TQMenuBar (this, "");
menubar.InsertItem ("&File", filemenu);
menubar.InsertItem ("&Shape", shapemenu);
menubar.InsertItem ("&Settings", settingsmenu);
}
}
public class Display: TQWidget, IQuantumFractal {
//Labels
TQLabel count;
TQLabel shape;
TQLabel alpha;
//Buttons
TQPushButton start;
TQPushButton stop;
TQPushButton reset;
TQPushButton gray;
TQPushButton intense;
//Drawable region
TQPaintBuffer buffer;
//Layouts
TQVBoxLayout layout;
TQHBoxLayout buttons;
TQVBoxLayout 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 (TQWidget parent): base (parent)
{
//Setup the sizes
TQSize size = new TQSize (resolution, resolution);
parent.SetBaseSize (size);
//Some nice colors
SetPaletteBackgroundColor (new TQColor ("Black"));
SetPaletteForegroundColor (new TQColor ("LightBlue"));
//Setup the buttons
start = new TQPushButton ("Start", this);
stop = new TQPushButton ("Stop", this);
reset = new TQPushButton ("Reset", this);
gray = new TQPushButton ("Color", this);
intense = new TQPushButton ("Intensity", this);
//Setup the labels
count = new TQLabel (this);
alpha = new TQLabel (this);
shape = new TQLabel (this);
//Setup the drawable
buffer = new TQPaintBuffer (this);
buffer.SetMinimumSize (size);
//Create the layouts
layout = new TQVBoxLayout (this);
buttons = new TQHBoxLayout (layout);
//Add some buttons
buttons.AddWidget (start);
buttons.AddWidget (stop);
buttons.AddWidget (reset);
buttons.AddWidget (gray);
buttons.AddWidget (intense);
//Connect the buttons and SlotQuit
TQObject.Connect (start, TQ_SIGNAL ("clicked()"),
this, TQ_SLOT ("SlotStart()"));
TQObject.Connect (stop, TQ_SIGNAL ("clicked()"),
this, TQ_SLOT ("SlotStop()"));
TQObject.Connect (reset, TQ_SIGNAL ("clicked()"),
this, TQ_SLOT ("SlotReset()"));
TQObject.Connect (gray, TQ_SIGNAL ("clicked()"),
this, TQ_SLOT ("SlotGray()"));
TQObject.Connect (intense, TQ_SIGNAL ("clicked()"),
this, TQ_SLOT ("SlotIntense()"));
TQObject.Connect (buffer, TQ_SIGNAL ("Painted()"),
this, TQ_SLOT ("SlotSetLabels()"));
TQObject.Connect (tqApp, TQ_SIGNAL ("lastWindowClosed ()"),
this, TQ_SLOT ("SlotQuit ()"));
//Layout labels
labels = new TQVBoxLayout (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 = TQFileDialog.GetSaveFileName (
TQDir.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 = TQInputDialog.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 (TQResizeEvent e)
{
int height = buffer.Size ().Height ();
int width = buffer.Size ().Width ();
resolution = height > width ? width : height;
}
}
[DeclareQtSignal ("Painted()")]
public class TQPaintBuffer : TQFrame {
//Drawables
private TQPixmap buffer;
private TQImage image;
//Timer
private TimerCallback call;
private Timer timer;
public TQPaintBuffer (TQWidget parent) : base (parent)
{
SetBackgroundMode (Qt.BackgroundMode.NoBackground);
//Create drawables
buffer = new TQPixmap ();
image = new TQImage (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 TQPixmap ();
image = new TQImage (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 (TQFocusEvent e)
{
PerformPaint ();
}
//Receive paint events
private void TouchPaint (TQPaintEvent e)
{
PerformPaint ();
}
//Receive resize events
private void TouchResize (TQResizeEvent e)
{
image = new TQImage (e.Size (), 32);
buffer.Resize (e.Size());
buffer.Fill (new TQColor("black"));
BitBlt (buffer, 0, 0, new TQPixmap (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;
}
}
}
}