I have a problem with sorting points by the angle they create with the X axis. The points look like this
Here is the code I have:
public static List<Point> SortPoints(List<Point> points)
{
List<Point> result = new List<Point>();
List<KeyValuePair<Point, double>> valuePairs = new List<KeyValuePair<Point, double>>();
foreach (var point in points)
{
valuePairs.Add(new KeyValuePair<Point, double>(point, Math.Atan2(point.Y, point.X)));
}
valuePairs = valuePairs.OrderByDescending(x => x.Value).ToList();
foreach (var valuepair in valuePairs)
{
result.Add(valuepair.Key);
}
return result;
}
It should sort points in the way, they close up. It works for most points, but it doesn't for some of them. It crashes mostly on these fragments:
Is my thinking correct for that kind of problem or do I miss something? I am still new to geometry in programming.
C# TRANSLATION
public static List<Point> SortPoints(List<Point> points)
{
double[] pnt = new double[points.Count * 2];
for (int z = 0, ii = 0; z < points.Count; z++, ii += 2)
{
pnt[ii] = points[z].X;
pnt[ii + 1] = points[z].Y;
}
int n2 = pnt.Length;
int n = n2 >> 1;
int[] idx = new int[n];
int i, j, k, i0, i1, e, m;
double a, x0, y0, x1, y1, x, y;
double[] ang = new double[n];
int[] flag = new int[n];
const double deg = Math.PI / 180.0;
const double thr = 0.02 * deg;
for (i = 0; i < n; i++) idx[i] = i + i;
x0 = x1 = pnt[0];
y0 = y1 = pnt[1];
for (i = 0; i < n2;)
{
x = pnt[i]; i++;
y = pnt[i]; i++;
if (x0 > x) x0 = x;
if (x1 < x) x1 = x;
if (y0 > y) y0 = y;
if (y1 < y) y1 = y;
}
x = 0.5 * (x0 + x1);
y = 0.5 * (y0 + y1);
for (i = 0, j = 0; i < n; i++, j += 2)
{
a = Math.Atan2(pnt[j + 1] - y, pnt[j + 0] - x);
ang[i] = a;
}
for (e = 1, j = n; e != 0; j--) // loop until jo swap occurs
for (e = 0, i = 1; i < j; i++) // proces unsorted part of array
if (ang[idx[i - 1] >> 1] > ang[idx[i] >> 1]) // condition if swap needed
{ e = idx[i - 1]; idx[i - 1] = idx[i]; idx[i] = e; e = 1; }
for (i = 0; i < n; i++) flag[i] = 0;
for (e = 0, j = 1, i = 1; i < n; i++)
if (Math.Abs(ang[idx[i] >> 1] - ang[idx[i - 1] >> 1]) < thr)
{ flag[idx[i] >> 1] = j; flag[idx[i - 1] >> 1] = j; e = 1; }
else if (e != 0) { e = 0; j++; }
if (e != 0) j++; m = j;
x = x0 + (0.3 * (x1 - x0));
y = 0.5 * (y0 + y1);
for (i = 0, j = 0; i < n; i++, j += 2)
if (flag[i] != 0) // only for problematic zones no need to recompute finished parts
{
a = Math.Atan2(pnt[j + 1] - y, pnt[j + 0] - x); // this might need handling edge cases of atan2
ang[i] = a;
}
for (k = 0; k < n;)
{
for (; k < n; k++) if (flag[idx[k] >> 1] != 0) // zone start
{
i0 = i1 = k;
for (; k < n; k++) if (flag[idx[k] >> 1] != 0) i1 = k;// // zone end
else break;
// index (bubble) sort idx[] asc by ang[]
if (i0 != i1)
for (e = 1, j = i1 - i0 + 1; e > 0; j--) // loop until jo swap occurs
for (e = 0, i = i0 + 1; i < i0 + j; i++) // proces unsorted part of array
if (ang[idx[i - 1] >> 1] > ang[idx[i] >> 1]) // condition if swap needed
{ e = idx[i - 1]; idx[i - 1] = idx[i]; idx[i] = e; e = 1; } // swap and allow to process array again
// different center for atan2 might reverse the ang order
// so test if start or end of zone is closer to the point before it
j = i0 - 1; if (j < 0) j = n - 1; // 45 deg is never at start or end of data so this should never happen
x = pnt[idx[j] + 0] - pnt[idx[i0] + 0];
y = pnt[idx[j] + 1] - pnt[idx[i0] + 1];
a = (x * x) + (y * y);
x = pnt[idx[j] + 0] - pnt[idx[i1] + 0];
y = pnt[idx[j] + 1] - pnt[idx[i1] + 1];
x = (x * x) + (y * y);
// reverse if not in correct order
if (x < a) for (; i0 < i1; i0++, i1--)
{ j = idx[i0]; idx[i0] = idx[i1]; idx[i1] = j; }
}
}
List<Point> result = new List<Point>();
for (int h = 0; h < pnt.Length - 1; h += 2)
{
result.Add(new Point(pnt[h], pnt[h + 1]));
}
return result;
}
Ok I got it working sorting by atan2 angle by using 2 centers only (no need for 3 as I can detect the problem zones directly from the first center alone). This is the algorithm (shape must not self intersect and angle around selected centers must be monotonic !!!):
compute BBOX (x0,y0,x1,y1) for your data
this is needed to properly compute correct center locations for atan2 usage
compute angle by atan2 for each point using BBOX center as center
the center should be inside your shape so center of BBOX is the obvious choice. However as Yves Daoust pointed out this will not work for arbitrary concave shapes only for those shapes and centers where the angle is monotonic.
sort your points by this angle
detect problematic zones
simply in problematic zones the consequent points after the sort has almost the same angle so just threshold that.
compute atan2 angle for each problem zone with different center
again center must be inside ... and should be shifted in any of the multiple of 90 degrees angle from original center. I chose shift toward x0 by 20% of shape x size. The bigger the shift the more ang difference the problem zones will get.
sort the problem zones by new angle
reverse problem zone order after sort if needed
the shifted center might cause the angle direction reversal in comparison to original angles. So after sort if you compute distance between point before zone and zone first and last point if the last point of zone is closer it means you need to reverse the zone points order.
Here preview of output:
Here C++/OpenGL/VCL code for this:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
#include "data.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
const int n2=sizeof(pnt)/sizeof(pnt[0]); // size of pnt[]
const int n=n2>>1; // point in pnt[]
int idx[n]; // index sort
int ix=1055; // just debug X cursor on mouse wheel
//---------------------------------------------------------------------------
void compute()
{
int i,j,k,i0,i1,e,m;
float a,x0,y0,x1,y1,x,y;
float ang[n]; // atan2 angles per point
int flag[n]; // 0 or problem zone ix per point
const float deg=M_PI/180.0;
const float thr=0.02*deg;
// shuffle input data for debug as its already ordered
for (i=0;i<n2;)
{
j=Random(n2)&0xFFFFFFFE;
a=pnt[i]; pnt[i]=pnt[j]; pnt[j]=a; i++; j++;
a=pnt[i]; pnt[i]=pnt[j]; pnt[j]=a; i++; j++;
}
// init index sort table
for (i=0;i<n;i++) idx[i]=i+i;
// compute BBOX of data
x0=x1=pnt[0];
y0=y1=pnt[1];
for (i=0;i<n2;)
{
x=pnt[i]; i++;
y=pnt[i]; i++;
if (x0>x) x0=x;
if (x1<x) x1=x;
if (y0>y) y0=y;
if (y1<y) y1=y;
}
// compute atan2 for center set to center of BBOX
x=0.5*(x0+x1);
y=0.5*(y0+y1);
for (i=0,j=0;i<n;i++,j+=2)
{
a=atan2(pnt[j+1]-y,pnt[j+0]-x); // this might need handling edge cases of atan2
ang[i]=a;
}
// index (bubble) sort idx[] asc by ang[]
for (e=1,j=n;e;j--) // loop until no swap occurs
for (e=0,i=1;i<j;i++) // process unsorted part of array
if (ang[idx[i-1]>>1]>ang[idx[i]>>1]) // condition if swap needed
{ e=idx[i-1]; idx[i-1]=idx[i]; idx[i]=e; e=1; } // swap and allow to process array again
// detect/label problematic zones m = number of zones +1
for (i=0;i<n;i++) flag[i]=0;
for (e=0,j=1,i=1;i<n;i++)
if (fabs(ang[idx[i]>>1]-ang[idx[i-1]>>1])<thr)
{ flag[idx[i]>>1]=j; flag[idx[i-1]>>1]=j; e=1; }
else if (e){ e=0; j++; }
if (e) j++; m=j;
// compute atan2 for center shifted toward x0
// so it still inside but not too close to (0,0)
// so there is some ang diference on problematic zones
x=x0+(0.3*(x1-x0));
y=0.5*(y0+y1);
for (i=0,j=0;i<n;i++,j+=2)
if (flag[i]) // only for problematic zones no need to recompute finished parts
{
a=atan2(pnt[j+1]-y,pnt[j+0]-x); // this might need handling edge cases of atan2
ang[i]=a;
}
// loop through problematic zones
for (k=0;k<n;)
{
for (;k<n;k++) if (flag[idx[k]>>1]) // zone start
{
i0=i1=k;
for (;k<n;k++) if (flag[idx[k]>>1]) i1=k; // zone end
else break;
// index (bubble) sort idx[] asc by ang[]
if (i0!=i1)
for (e=1,j=i1-i0+1;e;j--) // loop until no swap occurs
for (e=0,i=i0+1;i<i0+j;i++) // process unsorted part of array
if (ang[idx[i-1]>>1]>ang[idx[i]>>1]) // condition if swap needed
{ e=idx[i-1]; idx[i-1]=idx[i]; idx[i]=e; e=1; } // swap and allow to process array again
// different center for atan2 might reverse the ang order
// so test if start or end of zone is closer to the point before it
j=i0-1; if (j<0) j=n-1; // 45 deg is never at start or end of data so this should never happen
x=pnt[idx[j]+0]-pnt[idx[i0]+0];
y=pnt[idx[j]+1]-pnt[idx[i0]+1];
a=(x*x)+(y*y);
x=pnt[idx[j]+0]-pnt[idx[i1]+0];
y=pnt[idx[j]+1]-pnt[idx[i1]+1];
x=(x*x)+(y*y);
// reverse if not in correct order
if (x<a) for (;i0<i1;i0++,i1--)
{ j=idx[i0]; idx[i0]=idx[i1]; idx[i1]=j; }
}
}
}
//---------------------------------------------------------------------------
void gl_draw()
{
int i,j;
float a,da=1.0/float(n-1),x,y,r;
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
// set view to 2D
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0/120.0,1.0/120.0,1.0);
// render points from list
glBegin(GL_POINTS);
// glBegin(GL_LINE_STRIP);
// glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0,0.0,0.0);
glVertex2f(0.0,0.0);
for (a=0.0,i=0;i<n;i++,a+=da)
{
glColor3f(a,a,a);
glVertex2fv(pnt+idx[i]);
}
glEnd();
// render debug index (on mouse wheel)
x=pnt[idx[ix]+0];
y=pnt[idx[ix]+1];
r=5.0;
glBegin(GL_LINES);
glColor3f(0.0,1.0,0.0);
glVertex2f(x-r,y-r);
glVertex2f(x+r,y+r);
glVertex2f(x-r,y+r);
glVertex2f(x+r,y-r);
glEnd();
glFinish();
SwapBuffers(hdc);
Form1->Caption=ix;
}
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
// Init of program
gl_init(Handle); // init OpenGL
compute();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
// Exit of program
gl_exit();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
// repaint
gl_draw();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
// resize
gl_resize(ClientWidth,ClientHeight);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
Handled=true;
int dix=1; if (Shift.Contains(ssShift)) dix=10;
if (WheelDelta>0){ ix+=dix; if (ix>=n) ix= 0; }
if (WheelDelta<0){ ix-=dix; if (ix< 0) ix=n-1; }
gl_draw();
}
//---------------------------------------------------------------------------
Just ignore the VCL and OpenGL stuff. The only important stuff here is the function compute() which works as described above. The global variables just above it. I used index sort however so the points order is not changed at all instead idx[i] holds the index of i-th point in the input data. I wanted to keep this as simple as I could so no dynamic allocations nor containers or funny stuff... I used your data as input in form:
float pnt[]=
{
-98.622,0.4532042,
-98.622,1.64291,
-98.612097,3.0877569,
...
-98.618994,-3.2649391,
-98.6260115,-1.9205891
};
The gl_simple.h I used for OpenGL can be found here:
complete GL+GLSL+VAO/VBO C++ example
I tested this by using the cursor (green cross on image) and mouse wheel through the whole shape looking for jumping back and forward ... In previous versions I got the flag[] array as global and rendered different colors for the problem zones so I can debug directly them and not looking for whole shape again and again ... Also I used bubble sort ... in case you got huge data use quick sort instead... however this data you provided is computed instantly on my old computer so I didn't bother to add recursion.
For arbitrary concave non self-intersecting shapes you need to use different approach like for example connected component analysis:
for each point compute its 2 nearest neighbor points
this is very slow and should be speed-ed up by using spatial sorting of points to lower the complexity.
in case of very non uniform sampling the two closest points should not lie on or near the same direction!!! So dot between their unit direction should be as far from +1.0 as it can.
select any start point and add it to output
select one of its yet unused neighbors and add it to output
set link between selected and its predecessing point as used.
loop #4 until you get to the starting point again
Related
I have a 2d array of points (each point stored in my Points struct, which contains only 3 properties: X Y Z), with size of 128x128. I want to interpolate (stretch) this 2d array to greater size (132x132 for example). So far I have managed to interpolate X and Y coordinates of each point using linear interpolation (simply taking coordinates into array of double, interpolating it, and returning it to new 2d array of Points). Here is the code of linear interpolation:
private double[] InterpolateArray(double[] array, int newLength)
{
double[] result = new double[newLength];
result[0] = array[0];
result[newLength - 1] = array[array.Length - 1];
for (int i = 1; i < newLength - 1; i++)
{
double jd = ((double)i * (double)(array.Length - 1) / (double)(newLength - 1));
int j = (int)jd;
result[i] = array[j] + (array[j + 1] - array[j]) * (jd - (double)j);
}
return result;
}
Problem is that I have no idea how to interpolate Z coordinates of each point. Could that be done same way like X and Y coordinates? Or completely different approach is needed?
Edit: code for my Points struct:
public struct Points
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
public Points(double X, double Y, double Z)
{
this.X = X;
this.Y = Y;
this.Z = Z;
}
}
And code which does interpolation (or should do it at least):
public Points[,] Interpolate(Points[,] array, int newWidth, int newHeight)
{
Points[,] result = new Points[newWidth, newHeight];
double[] bufferBefore = new double[domes.GetLength(0)];
double[] bufferAfter = new double[newWidth];
for (int i = 0; i < domes.GetLength(1); i++)
{
for (int j = 0; j < domes.GetLength(0); j++)
{
bufferBefore[j] = domes[j, i].X;
}
bufferAfter = InterpolateArray(bufferBefore, newWidth);
for (int j = 0; j < newWidth; j++)
{
result[j, i].X = bufferAfter[j];
}
}
bufferBefore = new double[domes.GetLength(1)];
bufferAfter = new double[newHeight];
for (int i = 0; i < newWidth; i++)
{
for (int j = 0; j < domes.GetLength(1); j++)
{
bufferBefore[j] = result[i, j].Y;
}
bufferAfter = InterpolateArray(bufferBefore, newHeight);
for (int j = 0; j < newHeight; j++)
{
result[i, j].Y = bufferAfter[j];
}
}
return result;
}
I cannot see any way your current code is correct. In the second part you are doing bufferBefore[j] = result[i, j].Y;, but as far as I can see this has not been set anywhere before.
So when interpolating you need to interpolate all the values. So you would need to repeat the interpolation for each of x/y/z for each direction.
This however be done a bit simpler by implement the multiply operator for your point struct. This could allow you to do the interpolation for both x/y at once with code looking something like this:
public static Vector3 BilinearSample(this Vector3[,] self, in Vector2 point)
{
var xi = (int)Math.Floor(point.X);
var xi1 = xi + 1;
var xf = point.X - xi;
var yi = (int)Math.Floor(point.Y);
var yi1 = yi + 1;
var yf = point.Y - yi;
// You might need to add checks to ensure the sample is fully inside the image etc.
var v1 = self[xi, yi];
var v2 = self[xi1, yi];
var v3 = self[xi, yi1];
var v4 = self[xi1, yi1];
// Do the bilinear sample
var xfn1 = 1 - xf;
var v5 = v1 * xfn1 + v2 * xf;
var v6 = v3 * xfn1 + v4 * xf;
var result = v5 * (1 - yf) + v6 * yf;
return result;
}
I'm using System.Numerics instead of Point , but the principle is the same. Note that the above code would be identicalif you change the input/output type to Vector2 or double.
Also note that if the values represents direction or rotation you need to be careful, since the resulting directions might not be normalized after interpolation, and might even be zero.
I'm using Unity, and I'm making a generator in which the user inputs a degree of a polynomial plus all of its coefficients. For example, I can have degree 3 and [1,2,3,4], which should be 1x^3 + 2x^2 + 3x^1 + 4x^0.
Here's what I have:
int[] coef = TitleToGame.coeficients;
for (int x = -10; x <= 10; x++)
{
float y = 0;
for (int i = 0; i < TitleToGame.degree - 1; i++)
{
if (i == 0)
{
y = coef[TitleToGame.degree] * Mathf.Pow(x, i);
}
else
{
y += coef[TitleToGame.degree - i] * Mathf.Pow(x, i);
}
Instantiate(block, new Vector3(x, y, 5), Quaternion.identity);
}
}
I'm trying to generate blocks from domain -10 to 10. However, the result looks a bit funky.
Degree 3 with [1,1,1,1] shows a parabola with an extra linear line:
Degree 2 shows a linear line (with an extra unwanted flat line), 1 doesn't show anything, and 4 also shows a parabola. What am I doing wrong?
You're calling Instantiate in the inner for loop, when I persume you want to call it in the outer loop (from -10 to 10).
Also, you probably don't need that if-else statement. Both lines do the same thing.
for (int i = 0; i < TitleToGame.degree - 1; i++)
{
y += coef[TitleToGame.degree - i] * Mathf.Pow(x, i);
}
Instantiate(block, new Vector3(x, y, 5), Quaternion.identity);
So I have to make a program that prints how many times it has to make a certain calculation. However, when I print the result, I seem to be getting 16000 numbers that just add +1 every new time. My question is how to fix this. I have no idea...
Thank you for your help!
My code:
class Program
{
static void Main(string[] args)
{
double a = 0;
double b = 0;
double distance = 0;
int i = 1;
for (double x = -2; x < 2; x = x+0.01)
{
for (double y = -2; y < 2; y = y+ 0.01)
{
while(distance <= 2 || i < 100)
{
a = a * a - b * b + x;
b = 2 * a * b + y;
double a2b2 = Math.Pow(a, 2) + Math.Pow(b, 2);
distance = Math.Sqrt(a2b2);
i++;
}
Console.WriteLine(i);
}
}
Console.ReadKey();
}
}
I assume you're trying to plot a fractal of some description - I haven't checked the maths, but it reminds me of code I've used to generate Mandelbrot set images before now.
The problem is that you should be creating an independent calculation for each point - but you're maintaining the state of a, b, i and distance between points. That means once distance has become greater than 2 and i is greater than 100, you'll never get into the inside of the while loop. Just move the declaration and initialization of those variables to inside your inner for loop.
Additionally, the conditions for your while loop should be ANDed together rather than ORed together, assuming that the idea is to effectively limit it to 100 iterations per point.
for (double x = -2; x < 2; x += 0.01)
{
for (double y = -2; y < 2; y += 0.01)
{
// Initialize the local variables here, as they're meant to be independent for each point.
double a = 0;
double b = 0;
double distance = 0;
int i = 1;
while (distance <= 2 && i < 100)
{
a = a * a - b * b + x;
b = 2 * a * b + y;
double a2b2 = Math.Pow(a, 2) + Math.Pow(b, 2);
distance = Math.Sqrt(a2b2);
i++;
}
Console.WriteLine(i);
}
}
The double type means floating point type. See wiki. This type is not the right numeric type for precise addition like you use. Instead of that use decimal type.
I have text file that looks something like this
LINE 325,474 195,251 589,821 375,711 Nan Nan Nan
LINE 617,303 578,402 771,724 392,711 Nan Nan Nan
LINE 424,931 472,48 481,203 617,633 Nan Nan Nan
Where first column is basically name of element, second is starting X coordinate, third is starting Y coordinate, fourth and fifth are ending X and Y coordinates, others are not important.
I need to sort them by distance between each line. My code looks something like this:
string[] Text = File.ReadAllLines(OpenFile.Filename);
string[,] Word = new string[Text.Length, 8];
double CurXpos = 0; // for smallest distance set new points (starting from 0,0)
double CurYpos = 0;
string[] word = new string[8];
for (long i = 0; i < Text.Length; i++) // read text
{
string line = Text[i];
for (byte j = 0; j < 8; j++)
{
word = line.Split(' ');
Word[i, j] = word[j]; //store text to 2D array
}
}
StreamWriter FileSorted = new StreamWriter(desired destination);
for (long i = 0; i < Text.Length; i++) // search for minimal distance
{
double X1 = Math.Round(double.Parse(Word[i, 1], System.Globalization.CultureInfo.InvariantCulture), 3); // X start possition to double
double Y1 = Math.Round(double.Parse(Word[i, 2], System.Globalization.CultureInfo.InvariantCulture), 3); //Y , etc.
double X2 = Math.Round(double.Parse(Word[i, 3], System.Globalization.CultureInfo.InvariantCulture), 3);
double Y2 = Math.Round(double.Parse(Word[i, 4], System.Globalization.CultureInfo.InvariantCulture), 3);
double[] XPos = new double[Text.Length]; // array of smallest distances for each line
double[] YPos = new double[Text.Length];
double MinDis1 = Math.Sqrt(Math.Pow(X1 - CurXpos, 2) + Math.Pow(Y1 - CurXpos, 2)); //calculation of the smallest distances
double MinDis2 = Math.Sqrt(Math.Pow(X2 - CurXpos, 2) + Math.Pow(Y2 - CurYpos, 2)); //calculate if end points are closer
long PosMin = 0; //position of line with minimum
double[] AbsMinDis = new double[Text.Length]; // line containing distance data of each line
if (MinDis1 < MinDis2) // if distance of starting coordinate is smaller than ending, save
{
AbsMinDis[i] = MinDis1;
XPos[i] = X1;
YPos[i] = Y1;
}
else if (MinDis2 < MinDis1) // if distance of ending points is smaller, swap starting end endinng points and save line possition
{
AbsMinDis[i] = MinDis2;
XPos[i] = X2;
YPos[i] = Y2;
Word[i, 1] = X2.ToString();
Word[i, 2] = Y2.ToString();
Word[i, 3] = X1.ToString();
Word[i, 4] = Y1.ToString();
}
for (long j = 0; j < Text.Length; j++) //sorting file
{
if (AbsMinDis[i] < AbsMinDis[PosMin])
{
CurXpos = XPos[i];
CurYpos = YPos[i];
string swap = Word[PosMin, j];
Word[PosMin, j] = Word[i, j];
Word[i, j] = swap;
PosMin = i;
}
Now I don't know if I have there any error, or if I don't know how to write it, because it looks like, it does nothing with file
Writing looks like this:
FileSorted.Write(Word[i, 0]);
for (byte k = 1; k < 8; k++)
{
FileSorted.Write(" {0}", Word[i, k]);
}
FileSorted.WriteLine();
}
FileSorted.Close();
Thank you for your time and help.
There is a failure writing to SortedFile in other iterations of i (except the first) because you close the file at the end of iteration:
FileSorted.Close();
if you move FileSorted.Close() after you have done with all the iterations of i, then you will see all lines in the SortedFile.
The line duplication is because when writing to the file where you comment "//sorting file", you are writing the line i times instead of once.
And here you can see the capitalization conventions.
I feel like I'm missing something terribly obvious, but I cannot seem to find the array pair with the lowest value.
I have an int[,] worldMapXY where a 2D map is stored, say worldMapXY[0,0] through worldMapXY[120,120]. All values of map's array are 1 (wall\invalid) or 0 (path/valid).
I'm writing a method that will find coordinates in one of the eight cardinal directions to create a spawn point. So I also have int[,] validSpotArr which has a subset of bounds of the map closest to the direction I'm setting the spawn. The values for wall/invalid locations are set to 9999, the values for path/valid locations are set to (x + y). This is all specific to the bottom left corner, nearest to [0,0], hence "BL" or "Bottom Left"
case "BL":
for (int x = (int)border + 1; x < worldX + (int)border / 4; x++)
{
for (int y = (int)border + 1; y < worldY + (int)border / 4; y++)
{
if (worldMapXY[x,y] = 0)
{
validSpotArr[x,y] = x + y;
}
else
{
validSpotArr[x,y] = 9999;
}
}
}
What I can't quite wrap my head around is how to determine the coordinates/index of validSpotArr with the lowest value in such a way that I could pass those as separate x and y coordinates to another function (to set the spawn point). I suspect there's a lambda operator that may help, but I literally don't understand lambdas. Clearly that needs to be my next point of study.
E.g. - if validSpotArr[23, 45] = 68, and 68 is the lowest value, how do I set x=23 and y=45?
Edit: I tried messing around with something like this, but it isn't right:
Array.IndexOf(validSpotArr, validSpotArr.Min());
While not precisely an answer to your question, in a strictly given situation I'd probably go for finding those from within the cycles, i.e.
int minValidSpot = int.MaxValue, minX, minY;
for (int x = (int)border + 1; x < worldX + int(border) / 4; x++)
{
for (int y = (int)border + 1; y < worldY + int(border) / 4; y++)
{
if (worldMapXY[x,y] = 0)
{
validSpotArr[x,y] = x + y;
}
else
{
validSpotArr[x,y] = 9999;
}
if ( minValidSpot > validSpotArr[x,y] )
{
minValidSpot = validSpotArr[x,y];
minX = x;
minY = y;
}
}
}
Other than that, if looking for some kind of more universal solution, I'd probably just flatten that array, the maths for index conversion (nD<=>1D) are pretty simple.