Natural ChemE wrote:I’m working on a new CAD, and the first part that I’d like to tackle is the GUI. For funding reasons, it’s easier to have a shiny GUI and say “and, yeah, this function will work later once the engine is done” than it is to say “and this engine’s great, but you can't see it because the GUI hasn't been made yet”.
Making the forms, text boxes, menus, etc. is all really simple in C#. In fact it’s pretty much all down except for the hard part: the graphics area where users drag-and-drop unit operations, connect streams between the unit operations, etc. In this model the unit operations are pretty much like clip art or text boxes where they’ll have a body that can be translated and corners that can be dragged to resize them.
The issue here is that I don’t know how to do any of this. I made a program about a year ago that drew chemical structures (there’s a thread on it somewhere on this board), but it wasn’t very smooth despite the chemical structures being just different collections of text with lines drawn between them. And by “wasn’t very smooth”, I mean that when the user dragged or resized the chemical, you could see the graphics redrawing themselves; it looked unprofessionally laggy.
My main concern is that, if I repeat that methodology, then it’d look even more laggy since these new graphics will actually be icon-like instead of merely being text with lines. And while that’s not a fatal issue for a proof-of-concept GUI, I’d like to do it closer to right the first time through.
So, how can I make an efficient drag-and-drop-objects sort of GUI? Can it even be done in C#, or should I just use C++?
Side point: I know very little about how a computer handles graphics. I get the concept of the GPU and such, it’s just that I don’t get how code becomes implemented on the GPU, or how what I program becomes GPU-based code instead of CPU-based code. The abstraction layers are black boxes to me here.
CanadysPeak wrote:[..]why are you making a CAD? It's all been done quite well.
Natural ChemE wrote:The issue here is that I don’t know how to do any of this. I made a program about a year ago that drew chemical structures (there’s a thread on it somewhere on this board), but it wasn’t very smooth despite the chemical structures being just different collections of text with lines drawn between them. And by “wasn’t very smooth”, I mean that when the user dragged or resized the chemical, you could see the graphics redrawing themselves; it looked unprofessionally laggy.
...
So, how can I make an efficient drag-and-drop-objects sort of GUI? Can it even be done in C#, or should I just use C++?
Side point: I know very little about how a computer handles graphics. I get the concept of the GPU and such, it’s just that I don’t get how code becomes implemented on the GPU, or how what I program becomes GPU-based code instead of CPU-based code. The abstraction layers are black boxes to me here.
m_objDrawingSurface = new Bitmap(100, 100, System.Drawing.Imaging.PixelFormat.Format24bppRgb);Natural ChemE wrote:kidjan,
Thank you for your reply; sorry that mine's been so delayed.
First and last time I'd touched graphics (besides ASCII art-like graphs and such) was back when I did that chemical-drawing-program thingie. The old thread was Best way to draw chemicals in C#. Since I don't have the code for it on this computer, I'll have to resort to just copy/pasting what I had there:
- Code: Select all
m_objDrawingSurface = new Bitmap(100, 100, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Then if memory serves, there were DrawLine() and DrawText()-like commands which I used to draw onto that Bitmap. I then connected the drawing routine to a MouseDown() event (or something) so that, when the user dragged their mouse, it'd repaint the chemical in the new position. Also had a slider that resized it and another that rotated it, both using their own OnChange() or something events to trigger the redrawing.
Of relevance, they apparently hooked up their old drawing area to the .NET GUI. It's obviously the same control, and it's not laggy at all. Not sure if they did this for simple convenience (i.e., they already had made that part, why remake it?) or if they had a similar concern about .NET's laggier nature. (Side question: How would they have best hooked up their own control? Using ActiveX, COM, or what?)
I also figure that low-level's the way to go since that's what we write stuff like games in. I mean, something like Crysis running on a virtual machine language (.NET, Java, etc.) just wouldn't be viable, would it? I've always heard that games tend to run off custom-made low-level graphics engines tailored to that sorta game.
kidjan wrote:I'd bet the barn the sluggishness has more to do with improper threading than C#; one of the issues with C# is it makes it so easy to put together apps that a lot of programmers forget you still need to know something about Windows Forms if you want to have a responsive UI.
kidjan wrote:Most games aren't written purely in .NET, no, but plenty of games use stuff like XNA, which is a managed runtime environment. And yes, I think writing games in .NET or java is totally viable. After all, most of the acceleration comes from native, high-level APIs like OpenGL or DirectX--which you can call from nearly any language. The performance doesn't come from "using native code."
If you want to go low-level, go low-level. Sounds like that's what you want to do, so....go do it. But I wouldn't fool yourself into thinking simply swapping languages is going to solve your performance problems, or going "low level" will suddenly make everything better. It's a pretty common misconception in the field, frankly.
Natural ChemE wrote:If it is a misconception, then you’re right, it’s certainly a popular one. So much so that, from my asking around, I was led to believe that this was the consensus.
For instance I had an Aerospace professor insist that FORTRAN programs would always run at least twice as fast as C/C++ programs
Others have told me that there's simply no truth in that.
Anyway, if you’re reasonably sure about .NET being fine for the graphics, I’ll try it again for this project. Once I’m done I’ll share the code for it – and hopefully be able to report that it works well.
So, last question. If I use C# 4.5 on Visual Studio 2012 (may as well design for the future, right?), probably using WPF, what general approach would you recommend for the graphics area? i.e., what class should I use as a drawing board, what functions should I use to draw my objects, and, if you happen to have the time to make such a recommendation, where should I think about putting new thread calls?
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class PS6_P2 {
//condition options
static final int iterationCount = 10000; //25000
static final int pointCount = 100; //50
static final double boundaryDistanceFromCenter = 3.5;
static final double squareWellHalfWidth = 3.4;
static final double squareWellHeight = 250000.0;
static final double potentialInSquareWell = 0.0;
static final double initialStateStandardDeviation = 0.5; //smaller values result in a more needle-like initial distribution
static final double potentialWellCenter = 2.1;
//mathematical and physical constants
static final double mass = 1.0; //need to pick out
static final double pi = Math.PI;
static final double hbar = 1.0; //need to figure out units and fix this one //!!!
//output options
static final boolean ShowInitialConditionsGraph = false; //show a graph at the start with the initial distribution?
static final int graphHeight = 35; //= 45;//= 20; //needs to be at least (about) 10 (or else the space allotted to the actual graphing area is negative)
static final int graphWidth = 150; //= 200;//100; //needs to be at least (about) 10 (or else the space allotted to the actual graphing area is negative)
static final int printEveryThisManyGenerations = 10;//5000;
static final boolean showMatricesOnIteration = false; //WARNING: Tons of spam. Strongly suggested to use low point counts AND low iteration counts when set to 'true'.
static final boolean recordDataLog = false; //helps spare the hard drive if set to false when just watching movies
static final String dataLogFileName = "Data_log.txt";
static final boolean showSquaredWaveFunctionInGraphs = true; //show the squared wavefunction in the graphs?
static final boolean showRandIinIterationGraphs = false; //show the real and imaginary values in the graphs?
static final boolean showLegends = true; //show a legend below the graphs?
static final boolean useCustomFDomain = true; //if "true", uses "minFInGraphs" and "maxFInGraphs" for y-axis boundaries. if false, graph automatically uses data to determine y-axis boundaries (may shift scale each plot)
static final double minFInGraphs = 0.0; //"-1.0" is good if plotting real and imaginary components. "0.0" is good if just plotting squared wavefunction
static final double maxFInGraphs = 1.0;
//calculated values
static final int pointCountMinusOne = pointCount - 1;
static final double spaceStep = 2.0 * boundaryDistanceFromCenter / pointCountMinusOne;
static final double timeStep = spaceStep * 20000.0; //should probably calculate this for stability
static final double alpha = timeStep / (4.0 * mass * spaceStep * spaceStep);
static final double gamma = timeStep / (2.0 * mass * spaceStep * spaceStep);
static final double eta = timeStep / (2.0 * hbar);
//calculation method
static final boolean useTwoMatrices = true; //mathematically equivalent, but 'true' flag is faster (two NxN matrices instead of one 2Nx2N matrix)
@SuppressWarnings("unused")
public static void main(String argv[]){
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(dataLogFileName));
if(recordDataLog){writer.write("time");}
double[] x = new double[pointCount];
double[] R = new double[pointCount];
double[] I = new double[pointCount];
double[] V = new double[pointCount];
double[] modV = new double[pointCount];
double[] scriptR = new double[pointCount];
double[] scriptI = new double[pointCount];
double[] psiSq = new double[pointCount];
int matrixFarRightIndex;
int printIndex = 0, twoI;
Matrix matrix, matrix2;
if (useTwoMatrices){
matrixFarRightIndex = pointCount;
matrix = new Matrix(matrixFarRightIndex, matrixFarRightIndex + 1);
matrix2 = new Matrix(matrixFarRightIndex, matrixFarRightIndex + 1);
} else {
matrixFarRightIndex = 2 * pointCount;
matrix = new Matrix(matrixFarRightIndex, matrixFarRightIndex + 1);
}
Graph graph;
//setup initial values
for (int i=0; i<pointCount; i++){
x[i] = -boundaryDistanceFromCenter + spaceStep * (double)i;
if(Math.abs(x[i])<squareWellHalfWidth){R[i] = Math.exp(-(x[i]-potentialWellCenter)*(x[i]-potentialWellCenter) / (2.0 * initialStateStandardDeviation * initialStateStandardDeviation)) / (Math.sqrt(2.0 * Math.PI)*initialStateStandardDeviation);}
else {R[i] = 0.0;}
I[i] = 0.0; //? Not sure what to do for this one, but this works.
V[i] = (Math.abs(x[i])>squareWellHalfWidth)?squareWellHeight:potentialInSquareWell;
modV[i] = gamma + eta * V[i];
psiSq[i] = R[i] * R[i] + I[i] * I[i];
}
Normalize(x, R, I);
//graph initial values if it's called for
if(ShowInitialConditionsGraph){
graph = new Graph(graphHeight, graphWidth);
if(useCustomFDomain){graph.UseCustomFWindow(minFInGraphs, maxFInGraphs);}
//graph.Add(x, V, 'V', "Potential");
graph.Add(x, R, 'R', "Real component of wavefunction");
graph.Add(x, I, 'I', "Imaginary component of wavefunction");
graph.Add(x, psiSq, 'X', "Squared wavefunction");
graph.Print("Initial conditions");
if(showLegends){graph.PrintLegend();}
}
//write the header to the data log if it's called for
if (recordDataLog){
for (int i=0; i<pointCount; i++){
writer.write("\t" + x[i]);
}
writer.newLine();
writer.write(Double.toString(0.0));
for (int i=0; i<pointCount; i++){
writer.write("\t" + psiSq[i]);
}
}
//start iterating through time for the wave function
for (int iterationI=0; iterationI<iterationCount; iterationI++){
//clear matrix
if(useTwoMatrices){
for (int i=0; i<pointCount; i++){
for (int j=0; j<pointCount; j++){
matrix.M[i][j] = 0.0;
matrix2.M[i][j] = 0.0;
}
}
} else {
for (int i=0; i<2*pointCount; i++){
for (int j=0; j<2*pointCount; j++){
matrix.M[i][j] = 0.0;
}
}
}
//prepare data from prior generation
scriptR[0] = R[0] + modV[0] * I[0] - alpha * I[1];
scriptI[0] = I[0] - modV[0] * R[0] + alpha * R[1];
for (int i=1; i<pointCountMinusOne; i++){
scriptR[i] = R[i] - alpha * I[i-1] + modV[i] * I[i] - alpha * I[i+1];
scriptI[i] = I[i] + alpha * R[i-1] - modV[i] * R[i] + alpha * R[i+1];
}
scriptR[pointCountMinusOne] = R[pointCountMinusOne] - alpha * I[pointCountMinusOne-1] + modV[pointCountMinusOne] * I[pointCountMinusOne];
scriptI[pointCountMinusOne] = I[pointCountMinusOne] + alpha * R[pointCountMinusOne-1] - modV[pointCountMinusOne] * R[pointCountMinusOne];
//setup new matrix
// top row
// set far-right column
if (useTwoMatrices){
matrix.M[0][matrixFarRightIndex] = -scriptR[0];
matrix2.M[0][matrixFarRightIndex] = -scriptI[0];
// set R
matrix.M[0][0] = modV[0];
matrix.M[0][1] = -alpha;
// set I
matrix2.M[0][0] = -modV[0];
matrix2.M[0][1] = alpha;
} else {
matrix.M[0][matrixFarRightIndex] = -scriptR[0];
matrix.M[1][matrixFarRightIndex] = -scriptI[0];
// set R
matrix.M[0][1] = modV[0];
matrix.M[0][3] = -alpha;
// set I
matrix.M[1][0] = -modV[0];
matrix.M[1][2] = alpha;
}
// set in intermediate rows (all rows except for the first and the last)
for (int i=1; i<pointCountMinusOne; i++){
if (useTwoMatrices){
//set far-right column
matrix.M[i][matrixFarRightIndex] = -scriptR[i];
matrix2.M[i][matrixFarRightIndex] = -scriptI[i];
//set R
matrix.M[i][i-1] = -alpha;
matrix.M[i][i ] = modV[i];
matrix.M[i][i+1] = -alpha;
//set I
matrix2.M[i][i-1] = alpha;
matrix2.M[i][i ] = -modV[i];
matrix2.M[i][i+1] = alpha;
} else {
twoI = 2*i;
//set far-right column
matrix.M[twoI][matrixFarRightIndex] = -scriptR[i];
matrix.M[twoI+1][matrixFarRightIndex] = -scriptI[i];
//set R
matrix.M[twoI][twoI-1] = -alpha;
matrix.M[twoI][twoI+1] = modV[i];
matrix.M[twoI][twoI+3] = -alpha;
//set I
matrix.M[twoI+1][twoI-2] = alpha;
matrix.M[twoI+1][twoI] = -modV[i];
matrix.M[twoI+1][twoI+2] = alpha;
}
}
if (useTwoMatrices){
// bottom row
// set far-right column
matrix.M[pointCountMinusOne][matrixFarRightIndex] = -scriptR[pointCountMinusOne];
matrix2.M[pointCountMinusOne][matrixFarRightIndex] = -scriptI[pointCountMinusOne];
// set R
matrix.M[pointCountMinusOne][pointCountMinusOne-1] = -alpha;
matrix.M[pointCountMinusOne][pointCountMinusOne] = modV[pointCountMinusOne];
// set I
matrix2.M[pointCountMinusOne][pointCountMinusOne-1] = alpha; //these lines correct?
matrix2.M[pointCountMinusOne][pointCountMinusOne] = -modV[pointCountMinusOne];
} else {
// bottom row
// set far-right column
matrix.M[2*pointCountMinusOne][matrixFarRightIndex] = -scriptR[pointCountMinusOne];
matrix.M[2*pointCountMinusOne+1][matrixFarRightIndex] = -scriptI[pointCountMinusOne];
// set R
matrix.M[2*pointCountMinusOne][2*pointCountMinusOne-1] = -alpha;
matrix.M[2*pointCountMinusOne][2*pointCountMinusOne+1] = modV[pointCountMinusOne];
// set I
matrix.M[2*pointCountMinusOne+1][2*pointCountMinusOne-2] = alpha;
matrix.M[2*pointCountMinusOne+1][2*pointCountMinusOne] = -modV[pointCountMinusOne];
}
if (useTwoMatrices){
if(showMatricesOnIteration){matrix.Print("Matrix #1, pre-elimination"); matrix2.Print("Matrix #2, pre-elimination");}
//eliminate
matrix.SimpleGaussJordanElimination();
matrix2.SimpleGaussJordanElimination();
if(showMatricesOnIteration){matrix.Print("Matrix #1, post-elimination"); matrix2.Print("Matrix #2, post-elimination");}
} else {
if(showMatricesOnIteration){matrix.Print("Pre-elimination");}
//eliminate
matrix.SimpleGaussJordanElimination();
if(showMatricesOnIteration){matrix.Print("Post-elimination");}
}
if (useTwoMatrices){
//recover R and I
for (int i=0; i<pointCount; i++){
R[i] = matrix2.M[i][matrixFarRightIndex];
I[i] = matrix.M[i][matrixFarRightIndex];
}
} else {
//recover R and I
for (int i=0; i<pointCount; i++){
R[i] = matrix.M[2*i ][matrixFarRightIndex];
I[i] = matrix.M[2*i+1][matrixFarRightIndex];
}
}
//calculate squared wave function
for (int i=0; i<pointCount; i++){
psiSq[i] = R[i] * R[i] + I[i] * I[i];
}
if (recordDataLog){
writer.newLine();
writer.write(Double.toString(timeStep * (1.0+(double)iterationI)));
for (int i=0; i<pointCount; i++){
writer.write("\t" + psiSq[i]);
}
}
if(++printIndex>=printEveryThisManyGenerations){
printIndex = 0;
graph = new Graph(graphHeight, graphWidth);
if(useCustomFDomain){graph.UseCustomFWindow(minFInGraphs, maxFInGraphs);}
//graph.Add(x, V, 'V', "Potential");
if(showRandIinIterationGraphs){
graph.Add(x, R, 'R', "Real component of wavefunction");
graph.Add(x, I, 'I', "Imaginary component of wavefunction");
}
if(showSquaredWaveFunctionInGraphs){graph.Add(x, psiSq, 'X', "Squared wavefunction");}
graph.Print("Squared wavefunction at iteration #" + iterationI);
if(showLegends){graph.PrintLegend();}
}
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error: Could not create file " + dataLogFileName + ".");
}
}
private static void Normalize(double[] toNormalize){
int length = toNormalize.length;
double sum = 0.0;
for (int i=0; i<length; i++){sum += toNormalize[i];}
sum *= spaceStep;
for (int i=0; i<length; i++){toNormalize[i] /= sum;}
}
private static void Normalize(double[] x, double[] R, double[] I){
double sum = 0.0;
int loopCount = (R.length<I.length)?R.length:I.length;
for (int i=0; i<loopCount; i++){sum += R[i]*R[i] + I[i]*I[i];}
sum = Math.sqrt(sum * (x[loopCount-1]-x[0]) / (double)(loopCount-1));
for (int i=0; i<loopCount; i++){
R[i] /= sum;
I[i] /= sum;
}
}
}//The purpose of this class will be to provide a basic ASCII-art
//basis.
public class PrintSpace {
final static char voidCharacter = ' ';
final static char aloneCharacter = 'x';
final static char downArrow = 'v';
final static char upArrow = '^';
final static char leftArrow = '<';
final static char rightArrow = '>';
final static char rightDownDiagonal = '\\';
final static char rightUpDiagonal = '/';
final static char horizontalConnection = '-';
final static char verticalConnection = '|';
final static char hortizontalAndVerticalConnection = '+';
final static char bothDiagonalsConnection = 'X';
final static char majorConnector = 'X';
final static char unresolvedCharacter = '?';
char[][] space;
int[][] layer;
boolean[][] connection;
boolean resolutionIsFloating;
int height, width;
public PrintSpace(int height, int width){
this.height = height;
this.width = width;
space = new char[height][width];
layer = new int [height][width];
for (int i=0; i<height; i++){
for (int j=0; j<width; j++){
space[i][j] = voidCharacter;
layer[i][j] = 0;
}
}
resolutionIsFloating = false;
}
public void AddTextLeftAlign(String toAdd, int x, int y, int layer){
int printTo = (y+toAdd.length()<=width)?toAdd.length():width-y;
for (int i=0; i<printTo; i++){Add(toAdd.charAt(i), x, y+i, layer);}
}
public void AddTextCenterAlign(String toAdd, int x, int y, int layer){
int offset = toAdd.length() / 2;
int printTo = (y+toAdd.length()-offset<=width)?toAdd.length():width-y+offset;
for (int i=0; i<printTo; i++){Add(toAdd.charAt(i), x, y+i-offset, layer);}
}
//works but silly
/*public void AddTextBackwards(String toAdd, int x, int y, int layer){
int printTo = (y-toAdd.length()>=-1)?toAdd.length():y+1;
for (int i=0; i<printTo; i++){Add(toAdd.charAt(i), x, y-i, layer);}
}*/
public void Add(char toAdd, int x, int y, int layer){
if (layer >= this.layer[x][y]){this.space[x][y] = toAdd;}
}
public void DrawLine(int x1, int y1, int x2, int y2, int layer){
FloatLine(x1, y1, x2, y2);
Resolve(layer);
}
public void FloatLine (int x1, int y1, int x2, int y2){
int xDiff = x2-x1;
int yDiff = y2-y1;
int pointCount = ((xDiff>yDiff)?xDiff:yDiff)+1;
int[][] points = new int[pointCount][2];
//System.out.println(pointCount);
points[0][0] = x1;
points[0][1] = y1;
points[pointCount-1][0] = x2;
points[pointCount-1][1] = y2;
//System.out.println("Drawing from (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ").");
//System.out.println("Drawing at (" + points[0][0] + "," + points[0][1] + ")."); //!!! (to remove)
for (int i=1; i<pointCount-1; i++){
points[i][0] = x1 + (int)(Math.round(((double)xDiff) * (((double)(i))/((double)(pointCount-1)))));
points[i][1] = y1 + (int)(Math.round(((double)yDiff) * (((double)(i))/((double)(pointCount-1)))));
//System.out.println("Drawing at (" + points[i][0] + "," + points[i][1] + ")."); //!!! (to remove)
}
//System.out.println("Drawing at (" + points[points.length-1][0] + "," + points[points.length-1][1] + ")."); //!!! (to remove)
SetupResolve();
for (int i=0; i<pointCount; i++){
connection[points[i][0]][points[i][1]] = true;
}
}
private void SetupResolve(){
if (resolutionIsFloating) {return;}
connection = new boolean[height][width];
for (int i=0; i<height; i++){
for (int j=0; j<width; j++){
connection[i][j] = false;
}
}
resolutionIsFloating = true;
}
private char ResolvedCharacter (boolean[] positions){
//positions[] structure: //!!start
// [0] [1] [2]
// [3] X [4]
// [5] [6] [7]
//where "X" is the character to be determined
//this huge if{}else{} structure may look daunting, but it's basically just one case for
//each possible set of values for positions[], or 2^8=256 little branches.
//Long, sure, but very efficient for the computer.
if(positions[0]){
if(positions[1]){
if(positions[2]){
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
return majorConnector;
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return downArrow;
//return verticalConnection; //conflict again, think that the above is correct
}
} else {
if (positions[7]){
} else {
return downArrow;
}
}
}
}
}
} else {
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return verticalConnection;
}
} else {
if (positions[7]){
} else {
}
}
}
}
}
}
} else { //2TF
if(positions[2]){
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return horizontalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return rightArrow;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
return downArrow;
}
} else {
if (positions[7]){
return bothDiagonalsConnection;
} else {
return bothDiagonalsConnection;
//return rightArrow;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return bothDiagonalsConnection;
//return downArrow;
}
}
}
}
}
} else {
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return rightArrow;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return horizontalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return rightArrow;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return bothDiagonalsConnection;
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return rightDownDiagonal;
} else {
return rightDownDiagonal;
}
}
}
}
}
}
}
} else { //1F
if(positions[1]){
if(positions[2]){
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return verticalConnection;
}
} else {
if (positions[7]){
} else {
}
}
}
}
}
} else { //3FTF
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
} else {
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
} else {
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
return upArrow;
//return verticalConnection; //conflict, think this one is wrong
//this should be 1, 5, 6, 7
} else {
return verticalConnection;
}
} else {
if (positions[7]){
return upArrow;
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
return verticalConnection;
} else {
return verticalConnection;
}
} else {
if (positions[7]){
} else {
return verticalConnection;
}
}
}
}
}
}
} else { //2FF
if(positions[2]){
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return leftArrow;
} else {
return horizontalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return leftArrow;
} else {
}
}
}
}
} else {
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return leftArrow;
} else {
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
return rightUpDiagonal;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return leftArrow;
} else {
return rightUpDiagonal;
}
}
}
}
}
} else { //3FFF
if (positions[3]){
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
return horizontalConnection;
} else {
return horizontalConnection;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
} else {
if (positions[7]){
return horizontalConnection;
} else {
return horizontalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
} else {
if (positions[7]){
} else {
return horizontalConnection;
}
}
}
}
} else { //4FFFF
if (positions[4]){
if (positions[5]) {
if (positions[6]){
if (positions[7]){
} else {
}
} else {
if (positions[7]){
} else {
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return hortizontalAndVerticalConnection;
}
} else {
if (positions[7]){
} else {
return horizontalConnection;
}
}
}
} else {
if (positions[5]) {
if (positions[6]){
if (positions[7]){
return upArrow;
} else {
}
} else {
if (positions[7]){
return upArrow;
} else {
return rightUpDiagonal;
}
}
} else {
if (positions[6]){
if (positions[7]){
} else {
return verticalConnection;
}
} else {
if (positions[7]){
return rightDownDiagonal;
} else {
return aloneCharacter;
}
}
}
}
}
}
}
}
return majorConnector;
//return unresolvedCharacter;
}
private boolean IsInSpace(int x, int y){
//"(" + x + "," + y + ") is NOT in space (" + width + "," + height + ")");
if (x<0 || x>=height){return false;}
if (y<0 || y>=width ){return false;}
return true;
}
public void Resolve(int layer){
if(!resolutionIsFloating){return;}
boolean[] charR = new boolean[8];
//charR[] structure:
// [0] [1] [2]
// [3] X [4]
// [5] [6] [7]
for (int i=0; i<height; i++){
for (int j=0; j<width; j++){
if (connection[i][j]){
charR[0] = IsInSpace(i-1,j-1)?connection[i-1][j-1]:false;
charR[1] = IsInSpace(i-1,j )?connection[i-1][j ]:false;
charR[2] = IsInSpace(i-1,j+1)?connection[i-1][j+1]:false;
charR[3] = IsInSpace(i ,j-1)?connection[i ][j-1]:false;
charR[4] = IsInSpace(i ,j+1)?connection[i ][j+1]:false;
charR[5] = IsInSpace(i+1,j-1)?connection[i+1][j-1]:false;
charR[6] = IsInSpace(i+1,j )?connection[i+1][j ]:false;
charR[7] = IsInSpace(i+1,j+1)?connection[i+1][j+1]:false;
Add(ResolvedCharacter(charR), i, j, layer);
}
}
}
resolutionIsFloating = false;
}
public void FloatAll(){
SetupResolve();
for (int i=0; i<height; i++){
for (int j=0; j<width; j++){
if (space[i][j] != voidCharacter) {
connection[i][j] = true;
}
}
}
}
public void PushAllToLayer(int layer){
for (int i=0; i<height; i++){
for (int j=0; j<width; j++){
this.layer[i][j] = layer;
}
}
}
public void ReResolve(){
FloatAll(); //any int works
Resolve (0); //any int works
}
public void Print(){
for (int i=0; i<height; i++){
for (int j=0; j<width; j++){
System.out.print(space[i][j]);
}
System.out.println();
}
}
}import java.math.BigDecimal;
import java.math.MathContext;
public class Matrix {
protected double M[][];
protected int rowCount, colCount;
protected boolean unCol; //unconstrained/undefined columns, i.e., columns with all zero values
//for taking out suspected rounding errors
final private static double postNormalizationRoundingErrorThreshold = 1e-14;
public Matrix(double[][] matrix){
rowCount = matrix.length;
colCount = matrix[0].length;
M = new double[rowCount][colCount];
for (int i=0; i<rowCount; i++){
for (int j=0; j<colCount; j++){
M[i][j] = matrix[i][j];
}
}
}
public Matrix (double[] columnMatrix){
rowCount = columnMatrix.length;
colCount = 1;
M = new double[rowCount][colCount];
for (int i=0; i<rowCount; i++){
M[i][0] = columnMatrix[i];
}
}
public Matrix (int[] columnMatrix){
rowCount = columnMatrix.length;
colCount = 1;
M = new double[rowCount][colCount];
for (int i=0; i<rowCount; i++){
M[i][0] = (double)columnMatrix[i];
}
}
public Matrix(int height, int width){
M = new double[height][width];
ResetLengths();
}
public static Matrix Clone(Matrix matrixToClone){
return new Matrix(matrixToClone.M);
}
public Matrix Clone(){
return new Matrix(M);
}
public static void Print (double[][] matrix, String title){
int height = matrix.length, width = matrix[0].length;
if (title != "") {System.out.println(title.trim() + ":");}
for (int i=0; i<height; i++){
System.out.print("[ ");
for (int j=0; j<width; j++){
System.out.print(DD(matrix[i][j]) + " ");
}
System.out.println(" ]");
}
}
public void Print (String title){
if (title != "") {System.out.println(title.trim() + ":");}
for (int i=0; i<rowCount; i++){
System.out.print("[ ");
for (int j=0; j<colCount; j++){
System.out.print(DD(M[i][j]) + " ");
}
System.out.println(" ]");
}
}
private static String DD (double toDisplay){
String toReturn;
if (Double.isNaN(toDisplay)) {
toReturn = "NaN";
} else if (Double.isInfinite(toDisplay)){
toReturn = "Inf";
} else {
toReturn = BigDecimal.valueOf(toDisplay).round(new MathContext(3)).toString();
}
while (toReturn.length() < 10) {
toReturn += " ";
if (toReturn.length() < 10) {toReturn = " " + toReturn;}
}
return toReturn;
}
public static double[][] Normalize (double[][] matrixToNormalize){
double max, toReturn[][] = matrixToNormalize.clone();
int rowCount = toReturn.length, colCount = toReturn[0].length;
//rescale
//rescale diagonal elements to 1
for (int i=0; i<((rowCount<colCount)?rowCount:colCount); i++){for (int j=0; j<colCount; j++) {
toReturn[i][j] /= toReturn[i][i];
}}
//rescale elements beyond the diagonal by bringing max in row to 1
for (int i=colCount; i<rowCount; i++){
max = toReturn[i][0];
for (int j=1; j<colCount; j++) {if (toReturn[i][j] > max) {max = toReturn[i][j];}}
for (int j=0; j<colCount; j++) {toReturn[i][j] /= max;}
}
return toReturn;
}
public void Normalize(int numberOfColumnsOnTheRightToExclude){
//rescale based on the largest magnitude in a row that's not in an excluded column
int allowedColCount = colCount - numberOfColumnsOnTheRightToExclude;
int maxIndex;
double maxValue, thisValue;
for (int i=0; i<rowCount; i++){
maxIndex = -1;
maxValue = 0.0;
for (int j=0; j<allowedColCount; j++){
thisValue = Math.abs(this.M[i][j]);
if (thisValue > maxValue){
maxValue = thisValue;
maxIndex = j;
}
}
if (maxIndex < 0 || IsZero(maxValue)) {continue;} //don't normalize an all-zero row
maxValue = M[i][maxIndex]; //to get rid of the absolute value modification to the max value
for (int j=0; j<colCount; j++){
M[i][j] /= maxValue;
}
}
}
/*public void Normalize (){
double max, divisor;
double[] temp = new double[colCount];
//rescale
//rescale diagonal elements to 1
//System.out.println(colCount);
for (int i=0; i<((rowCount<colCount)?rowCount:colCount); i++){
divisor = M[i][i];
for (int j=0; j<colCount; j++) {
M[i][j] /= divisor;
}
}
//rescale elements beyond the diagonal by bringing max in row to 1
for (int i=colCount; i<rowCount; i++){
max = M[i][0];
for (int j=1; j<colCount; j++) {if (M[i][j] > max) {max = M[i][j];}}
for (int j=0; j<colCount; j++) {M[i][j] /= max;}
}
}*/
public static double[][] GaussJordanElimination (double[][] matrix){
//needs to be updated to be on-par with the non-static version
int rowCount = matrix.length, colCount = matrix[0].length;
double toReturn[][] = matrix.clone(), ratio, max;
//System.out.println(matrix[0][1]);
//eliminate
for (int k=0; k<rowCount; k++){
for (int i=0; i<rowCount; i++){if (i!=k && i<colCount && k<colCount){
ratio = toReturn[i][k] / toReturn[k][k];
for (int j=0 ; j<colCount; j++) {toReturn[i][j] -= ratio*toReturn[k][j];}
}}
}
//rescale diagonal elements to 1
for (int i=0; i<((rowCount<colCount)?rowCount:colCount); i++){for (int j=0; j<colCount; j++) {
toReturn[i][j] /= toReturn[i][i];
}}
//rescale elements beyond the diagonal by bringing max in row to 1
for (int i=colCount; i<rowCount; i++){
max = matrix[i][0];
for (int j=1; j<colCount; j++) {if (matrix[i][j] > max) {max = matrix[i][j];}}
for (int j=0; j<colCount; j++) {matrix[i][j] /= max;}
}
return toReturn;
}
private void EliminateZeroRows(){
boolean[] allZeros = new boolean[rowCount];
int nonZeroRowCount = rowCount;
for (int i=0; i<rowCount; i++){
allZeros[i] = true;
for (int j=0; j<colCount; j++){
if(!IsZero(M[i][j])) {allZeros[i] = false; break;}
}
if (allZeros[i]) {nonZeroRowCount--;}
}
if(nonZeroRowCount == rowCount) {return;}
double[][] newM = new double[nonZeroRowCount][colCount];
int newRowIndex = 0;
for (int i=0; i<rowCount; i++){
if(!allZeros[i]){
for (int j=0; j<colCount; j++){
newM[newRowIndex][j] = M[i][j];
}
newRowIndex++;
}
}
M = newM;
ResetLengths();
}
private boolean IsZero(double toTestForBeingZero){
//may want to redefine this to include near-zero values too, so this function
//is provided for updating purposes
if (toTestForBeingZero == 0) {return true;}
return false;
}
private int NonZeroRow(int columnToFindNonZeroRowFor){
for (int i=0; i<colCount; i++){
if (!IsZero(M[i][columnToFindNonZeroRowFor])){return i;}
}
return -1;
}
public void PrimitiveRoundingErrorCleanUp(){
for (int i=0; i<rowCount; i++){
for (int j=0; j<colCount; j++){
if(Math.abs(M[i][j])<postNormalizationRoundingErrorThreshold){M[i][j] = 0.0;}
}
}
}
public void Invert(){
if (colCount != rowCount) {return;}
Matrix temp = new Matrix(rowCount, 2 * colCount);
for (int i=0; i<rowCount; i++){
for (int j=0; j<colCount; j++){
temp.M[i][j] = M[i][j];
temp.M[i][colCount+j] = 0.0;
}
temp.M[i][colCount+i] = 1.0;
}
temp.SimpleGaussJordanElimination();
for (int i=0; i<rowCount; i++){
for (int j=0; j<colCount; j++){
M[i][j] = temp.M[i][colCount+j];
}
}
}
public void Add(Matrix toAdd){
int toAddRowCount=(rowCount<toAdd.rowCount)?rowCount:toAdd.rowCount, toAddColCount=(colCount<toAdd.colCount)?colCount:toAdd.colCount;
for (int i=0; i<toAddRowCount; i++){
for (int j=0; j<toAddColCount; j++){
M[i][j] += toAdd.M[i][j];
}
}
}
public static Matrix Add(Matrix toAdd1, Matrix toAdd2){
int toAddRowCount=(toAdd1.rowCount<toAdd2.rowCount)?toAdd1.rowCount:toAdd2.rowCount, toAddColCount=(toAdd1.colCount<toAdd2.colCount)?toAdd1.colCount:toAdd2.colCount;
Matrix toReturn = new Matrix(toAddRowCount, toAddColCount);
for (int i=0; i<toAddRowCount; i++){
for (int j=0; j<toAddColCount; j++){
toReturn.M[i][j] = toAdd1.M[i][j] + toAdd2.M[i][j];
}
}
return toReturn;
}
public void Subtract(Matrix toAdd){
int toAddRowCount=(rowCount<toAdd.rowCount)?rowCount:toAdd.rowCount, toAddColCount=(colCount<toAdd.colCount)?colCount:toAdd.colCount;
for (int i=0; i<toAddRowCount; i++){
for (int j=0; j<toAddColCount; j++){
M[i][j] -= toAdd.M[i][j];
}
}
}
public static Matrix Subtract(Matrix toAdd1, Matrix toAdd2){
int toAddRowCount=(toAdd1.rowCount<toAdd2.rowCount)?toAdd1.rowCount:toAdd2.rowCount, toAddColCount=(toAdd1.colCount<toAdd2.colCount)?toAdd1.colCount:toAdd2.colCount;
Matrix toReturn = new Matrix(toAddRowCount, toAddColCount);
for (int i=0; i<toAddRowCount; i++){
for (int j=0; j<toAddColCount; j++){
toReturn.M[i][j] = toAdd1.M[i][j] - toAdd2.M[i][j];
}
}
return toReturn;
}
public void Multiply(Matrix toMult){
if (colCount!=toMult.rowCount){return;}
double[][] temp = new double[rowCount][toMult.colCount];
for (int i=0; i<rowCount; i++){
for (int j=0; j<toMult.colCount; j++){
for (int k=0; k<colCount; k++){
temp[i][j] += M[i][k] * toMult.M[k][j];
}
}
}
M = temp;
ResetLengths();
}
public static Matrix Multiply(Matrix toMult1, Matrix toMult2){
if (toMult1.colCount!=toMult2.rowCount){return new Matrix(new double[][] {});}
Matrix toReturn = new Matrix(toMult1.rowCount, toMult2.colCount);
for (int i=0; i<toMult1.rowCount; i++){
for (int j=0; j<toMult2.colCount; j++){
toReturn.M[i][j] = 0.0;
for (int k=0; k<toMult1.colCount; k++){
toReturn.M[i][j] += toMult1.M[i][k] * toMult2.M[k][j];
}
}
}
return toReturn;
}
public void Multiply(double scaler){
for (int i=0; i<rowCount; i++){
for (int j=0; j<colCount; j++){
M[i][j] *= scaler;
}
}
}
public static Matrix Multiply(double scaler, Matrix matrix){
Matrix toReturn = new Matrix(matrix.rowCount, matrix.colCount);
for (int i=0; i<matrix.rowCount; i++){
for (int j=0; j<matrix.colCount; j++){
toReturn.M[i][j] = scaler * matrix.M[i][j];
}
}
return toReturn;
}
public static Matrix Identity (int length){
Matrix toReturn = new Matrix(length, length);
for (int i=0; i<length; i++){
for (int j=0; j<length; j++){
toReturn.M[i][j] = (i==j)?1:0;
}
}
return toReturn;
}
public void Transpose(){
double[][] temp = new double[colCount][rowCount];
for (int i=0; i<rowCount; i++) {
for (int j=0; j<rowCount; j++) {
temp[j][i] = M[i][j];
}
}
M = temp;
ResetLengths();
}
public static Matrix Transpose(Matrix toTranspose){
Matrix toReturn = new Matrix(toTranspose.colCount, toTranspose.rowCount);
for (int i=0; i<toTranspose.rowCount; i++) {
for (int j=0; j<toTranspose.rowCount; j++) {
toReturn.M[j][i] = toTranspose.M[i][j];
}
}
return toReturn;
}
private void ResetLengths(){
rowCount = M.length;
colCount = M[0].length;
}
public void SimpleGaussJordanElimination(){
//Normalize();
GeneralGaussJordanElimination(1);
Sort();
//Normalize();
PrimitiveRoundingErrorCleanUp();
}
public void GeneralGaussJordanElimination(int countOfColumnsOnTheRightToNotUseInElimination){
double ratio, maxValue, thisValue;
int columnsToEliminateWith = (colCount - countOfColumnsOnTheRightToNotUseInElimination<rowCount)?colCount - countOfColumnsOnTheRightToNotUseInElimination:rowCount;
int maxIndex;
boolean ledToByZeros;
//EliminateZeroRows();
//normalize
Normalize(countOfColumnsOnTheRightToNotUseInElimination);
PrimitiveRoundingErrorCleanUp();
for (int i=0; i<columnsToEliminateWith; i++){
//Print("Before iteration #" + i);
//find max magnitude in column
maxIndex = -1;
maxValue = 0.0;
for (int j=0; j<rowCount; j++){
ledToByZeros = true;
for (int k=0; k<i; k++){
if(!IsZero(M[j][k])){ledToByZeros = false; break;}
}
if (!ledToByZeros) {continue;}
thisValue = Math.abs(M[j][i]);
if (thisValue > maxValue){
maxIndex = j;
maxValue = thisValue;
}
}
//skip this iteration if the max is a zero
if (IsZero(maxValue) || maxIndex < 0){continue;}
//eliminate based on this row
for (int j=0; j<rowCount; j++){
if (j==maxIndex) {continue;}
ratio = M[j][i] / M[maxIndex][i];
for (int k=0; k<colCount; k++){
M[j][k] -= ratio * M[maxIndex][k];
}
}
//normalize
Normalize(countOfColumnsOnTheRightToNotUseInElimination);
PrimitiveRoundingErrorCleanUp();
}
//Print("Post-elimination");
}
public void Sort(){
int columnToSortTo = (colCount < rowCount) ? colCount:rowCount, maxIndex;
double maxValue, thisValue;
for (int i=0; i<columnToSortTo; i++){
maxIndex = i;
maxValue = Math.abs(M[i][i]);
for (int j=i+1; j<rowCount; j++){
thisValue = Math.abs(M[j][i]);
if (thisValue > maxValue){
maxIndex = j;
maxValue = thisValue;
}
}
if(maxIndex>i){SwapRows(i, maxIndex);}
}
}
public void SwapRows (int firstRowIndex, int secondRowIndex){
double temp;
for (int i=0; i<colCount; i++){
temp = M[firstRowIndex][i];
M[firstRowIndex][i] = M[secondRowIndex][i];
M[secondRowIndex][i] = temp;
}
}
public void GaussJordanEliminationOld(){
double ratio;
EliminateZeroRows();
//NonZeroRow(i)
int thisRow;
/*for (int i=0; i<colCount; i++){
thisRow = NonZeroRow(i);
if (thisRow == -1) {continue;}
for (int j=0; j<rowCount; j++){
if (j != thisRow){
ratio = M[j][i] / M[thisRow][i];
for (int k=0; k<colCount; k++){
M[j][k] -= ratio * M[thisRow][k];
}
}
}
EliminateZeroRows();
Print("After iteration #" + i);
}*/
//eliminate
for (int k=0; k<rowCount && k<colCount; k++){
for (int i=0; i<rowCount; i++){
if (i!=k){
if (i<colCount){
ratio = M[i][k] / M[k][k];
for (int j=0 ; j<colCount; j++) {M[i][j] -= ratio*M[k][j];}
} else {
//add further elimination for non-square matrices
}
}
}
EliminateZeroRows();
}
//EliminateZeroRows();
Normalize(1); //dunno, didn't require an argument back when this was made
//old normalization function has been obsoleted and replaced
//it used to just normalize based on the diagonals
}
}import java.math.BigDecimal;
import java.math.MathContext;
public class Graph {
int bottomIndex, topIndex, leftIndex, rightIndex;
int functionCount, leftLabelLength;
double minX, maxX, minF, maxF;
double setMinX, setMaxX, setMinF, setMaxF;
boolean useCustomXDomain, useCustomFDomain;
PrintSpace graph, legend; //legend is separate for now
String[] functions;
char[] markers;
char verticalTick = '-';
char horizontalTick = '|';
private static final String legendTitle = "Legend";
double[][][] data; //data[function index][point index][0 for x, 1 for f]
public Graph(int height, int width){
leftLabelLength = 8;
//bottomIndex = maxBottom - 3;
//topIndex = 1;
//leftIndex = 3;
//rightIndex = maxRight - 1;
graph = new PrintSpace(height, width);
functionCount = 0;
functions = new String[0];
markers = new char[0];
data = new double[0][][];
}
public void UseCustomXWindow(double minX, double maxX){
this.setMinX = minX;
this.setMaxX = maxX;
useCustomXDomain = true;
}
public void UseCustomFWindow(double minF, double maxF){
this.setMinF = minF;
this.setMaxF = maxF;
useCustomFDomain = true;
}
public void UseAutoXWindow(){
useCustomXDomain = false;
}
public void UseAutoFWindow(){
useCustomFDomain = false;
}
public void Add(double[] x, double[] f, char marker, String functionName){
functionCount++;
AddFunctionName(functionName);
AddFunctionData(x, f);
AddMarker(marker);
}
private void AddFunctionName(String toAdd){
String[] temp = new String[functions.length + 1];
for (int i=0; i<functions.length; i++){temp[i] = functions[i];}
temp[functions.length] = toAdd;
functions = temp;
}
private void AddFunctionData(double[] x, double[] f){
double[][][] temp = new double[data.length+1][][];
int toAddLength = (x.length<f.length)?x.length:f.length;
double[][] temp2 = new double[toAddLength][2];
for (int i=0; i<data.length; i++){temp[i] = data[i];}
for (int i=0; i<toAddLength; i++){
temp2[i][0] = x[i];
temp2[i][1] = f[i];
}
temp[data.length] = temp2;
data = temp;
}
private void AddMarker(char marker){
char[] temp = new char[markers.length+1];
for (int i=0; i<markers.length; i++){temp[i] = markers[i];}
temp[markers.length] = marker;
markers = temp;
}
private void GetExtremes(){
boolean bothSet = false;
if(useCustomXDomain){
minX = setMinX;
maxX = setMaxX;
bothSet = true;
} else {
minX=0.0;
maxX=0.0;
}
if(useCustomFDomain){
minF = setMinF;
maxF = setMaxF;
if (bothSet) {return;}
} else {
minF=0.0;
maxF=0.0;
}
boolean firstFound = false;
//set initial values (searches data for a value; there may be empty data sets and don't want ArrayOutOfBounds!)
for (int i=0; i<data.length; i++){
for (int j=0; j<data[i].length; j++){
firstFound = true;
if(!useCustomXDomain){minX = maxX = data[i][j][0];}
if(!useCustomFDomain){minF = maxF = data[i][j][1];}
break;
}
if (firstFound) break;
}
if (!firstFound) {return;}
//look for actual mins and maxs
for (int i=0; i<data.length; i++){
for (int j=0; j<data[i].length; j++){
if(!useCustomXDomain){
if (data[i][j][0]<minX) {minX = data[i][j][0];}
if (data[i][j][0]>maxX) {maxX = data[i][j][0];}
}
if(!useCustomFDomain){
if (data[i][j][1]<minF) {minF = data[i][j][1];}
if (data[i][j][1]>maxF) {maxF = data[i][j][1];}
}
}
}
}
private void AddPointsToGraph(){
if(minX == maxX) {return;}
if(minF == maxF) {return;}
int yToAdd, xToAdd;
//System.out.println(minX + "," + maxX + "," + minF + "," + maxF);
for (int i=0; i<data.length; i++){
for (int j=0; j<data[i].length; j++){
//System.out.println(ToGraphIndexY(data[i][j][1], minF, maxF));
//graph.Add(markers[i], ToGraphIndexX(data[i][j][0], minX, maxX), ToGraphIndexY(data[i][j][1], minF, maxF), i);
yToAdd = ToGraphIndexY(data[i][j][1], minF, maxF);
xToAdd = ToGraphIndexX(data[i][j][0], minX, maxX);
if(yToAdd>bottomIndex||yToAdd<topIndex){continue;}
if(xToAdd>rightIndex||xToAdd<leftIndex){continue;}
graph.Add(markers[i], yToAdd, xToAdd, i);
//ToGraphIndexX(data[i][j][0], minX, maxX);
//ToGraphIndexY(data[i][j][1], minF, maxF);
}
}
}
private void AddFrame(){
//Set box coordinates
bottomIndex = graph.height - 3;
topIndex = 0;
leftIndex = leftLabelLength + 1;
rightIndex = graph.width - 3;
//Box
graph.FloatLine(topIndex, leftIndex, bottomIndex, leftIndex);
graph.FloatLine(topIndex, leftIndex, topIndex, rightIndex);
graph.FloatLine(topIndex, rightIndex, bottomIndex, rightIndex);
graph.FloatLine(bottomIndex, leftIndex, bottomIndex, rightIndex);
graph.Resolve(0);
//x-axis ticks
graph.Add(horizontalTick, bottomIndex+1, leftIndex, 0);
graph.Add(horizontalTick, bottomIndex+1, rightIndex, 0);
//y-axis ticks
graph.Add(verticalTick, topIndex, leftIndex-1, 0);
graph.Add(verticalTick, bottomIndex, leftIndex-1, 0);
//x-axis labels
graph.AddTextCenterAlign(DDBottomLabel(minX), bottomIndex+2, leftIndex, 0);
graph.AddTextCenterAlign(DDBottomLabel(maxX), bottomIndex+2, rightIndex, 0);
//y-axis labels
graph.AddTextLeftAlign(DDLeftLabel(maxF), topIndex, 0, 0);
graph.AddTextLeftAlign(DDLeftLabel(minF), bottomIndex, 0, 0);
}
public void Print(String title){
System.out.println(title + ":");
Print();
}
public void Print(){
GetExtremes();
AddFrame();
AddPointsToGraph();
graph.Print();
}
/*private int ToGraphIndexX(double x, double minX, double maxX){
System.out.println("f: " + (leftIndex + (int)Math.round(((double)(rightIndex-leftIndex))*(x-minX)/(maxX-minX))));
return leftIndex + (int)Math.round(((double)(rightIndex-leftIndex))*(x-minX)/(maxX-minX));
}
private int ToGraphIndexY(double y, double minY, double maxY){
System.out.println("x: " + (bottomIndex + (int)Math.round(((double)(topIndex-bottomIndex))*(y-minY)/(maxY-minY))));
return bottomIndex + (int)Math.round(((double)(topIndex-bottomIndex))*(y-minY)/(maxY-minY));
}*/
private int ToGraphIndexX(double x, double minX, double maxX){
//System.out.println("x: " + (leftIndex + (int)Math.round(((double)(rightIndex-leftIndex))*(x-minX)/(maxX-minX))));
return leftIndex + (int)Math.round((double)(rightIndex-leftIndex)*(x-minX)/(maxX-minX));
}
private int ToGraphIndexY(double y, double minY, double maxY){
//System.out.println("Y: " + (bottomIndex + (int)Math.round(((double)(topIndex-bottomIndex))*(y-minY)/(maxY-minY))));
return bottomIndex + (int)Math.round((double)(topIndex-bottomIndex)*(y-minY)/(maxY-minY));
}
private String DDLeftLabel (double toDisplay){
String toReturn;
if (Double.isNaN(toDisplay)) {
toReturn = "NaN";
} else if (Double.isInfinite(toDisplay)){
toReturn = "Inf";
} else {
toReturn = BigDecimal.valueOf(toDisplay).round(new MathContext(leftLabelLength-5)).toString();
}
while (toReturn.length() < leftLabelLength) {
toReturn = " " + toReturn;
}
return toReturn;
}
private void CreateLegend(){
if (functions.length < 1) {
System.out.println("No function names for legend.");
return;
}
int maxStringLength = legendTitle.length();
int legendHeight, legendWidth;
for (int i=0; i<functions.length; i++){
if(functions[i].length() > maxStringLength) {maxStringLength = functions[i].length();}
}
legendHeight = functions.length + 4;
legendWidth = maxStringLength + 7;
int xOffset = (graph.width-legendWidth)/2;
if (xOffset<0) {xOffset =0;}
legend = new PrintSpace(legendHeight, legendWidth+xOffset);
legend.FloatLine(0, xOffset, 0, legendWidth-1+xOffset);
legend.FloatLine(0, legendWidth-1+xOffset, legendHeight-1, legendWidth-1+xOffset);
legend.FloatLine(0, xOffset, legendHeight-1, xOffset);
legend.FloatLine(legendHeight-1, xOffset, legendHeight-1, legendWidth-1+xOffset);
legend.Resolve(0);
legend.FloatLine(2, xOffset, 2, legendWidth-1+xOffset);
legend.Resolve(0);
legend.AddTextLeftAlign(legendTitle, 1, 2+xOffset, 0);
for (int i=0; i<functions.length; i++){
legend.AddTextLeftAlign(markers[i] + ": " + functions[i], 3+i, 2+xOffset, 0);
}
}
public void PrintLegend(){
CreateLegend();
legend.Print();
}
private String DDBottomLabel (double toDisplay){
String toReturn;
if (Double.isNaN(toDisplay)) {
toReturn = "NaN";
} else if (Double.isInfinite(toDisplay)){
toReturn = "Inf";
} else {
toReturn = BigDecimal.valueOf(toDisplay).round(new MathContext(leftLabelLength)).toString();
}
while (toReturn.length() < leftLabelLength) {
toReturn += " ";
if (toReturn.length() < leftLabelLength) {toReturn = " " + toReturn;}
}
return toReturn;
}
}Image toAdd = new Image();tics[i, j].Source = board.image(i, j);Visual Studio 2010 wrote:InvalidOperationException occurred
The calling thread cannot access this object because a different thread owns it.
If only one thread can modify the UI, how do background threads interact with the user? A background thread can ask the UI thread to perform an operation on its behalf. It does this by registering a work item with the Dispatcher of the UI thread. The Dispatcher class provides two methods for registering work items: Invoke and BeginInvoke. Both methods schedule a delegate for execution. Invoke is a synchronous call – that is, it doesn’t return until the UI thread actually finishes executing the delegate. BeginInvoke is asynchronous and returns immediately.
tics[i, j].Source = board.image(i, j);
tics[i, j].Tag = board.ASCII(i, j);SetImageCallback cb = new SetImageCallback(setImage);
grid.Dispatcher.BeginInvoke(cb, new point(i, j));private void setImage(point location)
{
tics[location.x, location.y].Source = board.image(location.x, location.y);
tics[location.x, location.y].Tag = board.ASCII(location.x, location.y);
}Edit - Changed "this.Dispatcher" to "grid.Dispatcher". I'm guessing that directly accessing the grid would be faster than routing everything through the form.
I'm debating if I should start a company on this one or just open source it.kidjan wrote:Glad to be of help. Let me know if you want to do some open source dev; I'm always looking for fun projects.
Users browsing this forum: Heritrix [Crawler] and 1 guest