I could use some help creating some points for a sliced circle, I'm having a total brainfart and just can't figure it out.
I want to create a "field of view" circle for a game ai and would like to create the points in an alternating pattern covering roughly a Pi*1.75 area.
To make alternate rays, you can use parity of counter. Pseudocode
n = 11
for (i = 1; i <= n; i++) {
int j = i / 2
float angle = - j * Pi * 7 / 4 / n
if (i & 1)
angle = - angle
line end:
X = CX + R * Cos(angle - Pi/2))
Y = CY + R * Sin(angle - Pi/2))
working Delphi code for demonstration:
var
n, i, X, Y: Integer;
a: Double;
begin
n := 11;
for i := 1 to n do begin
Canvas.MoveTo(200, 200);
a := (i div 2)* Pi * 7 / 4 / n;
if (i and 1 = 0) then
a := - a;
X := 200 + Round(100 * Cos(a - Pi/2));
Y := 200 + Round(100 * Sin(a - Pi/2));
Canvas.LineTo(X, Y);
Canvas.TextOut(X, Y, i.ToString);
end;
Related
So I'm running iterations with this formula:
double x = 10 / 0.25 * ((0.0002 * x1 * (10 - 0.25 * x1)) + 0.00217 * x2 * (20 - 0.25 * x2)); With this process: Xn+1 = f(Xn).
And if you start from negative X you will eventually end up with (-/+) infinity, so after 6 iterations I'm supposed to get infinity, but what I got surprised me and I couldn't find anywhere what that is, I got "-?", I've tried comparing it to +/- infinity and tried to compare it to int numbers just to clarify what it is, but I cant get anything out of it, for example, I've tried if ("-?" > 1000) break;, and it doesn't outcome as "true". Neither am I getting any errors by comparing it to int/double, I need to stop iterations when I start going into infinity, how can I do that?
code:
public static double CalculateX1(double x1, double x2)
{
double x = 10 / 0.25 * ((0.0002 * x1 * (10 - 0.25 * x1)) + 0.00217 * x2 * (20 - 0.25 * x2));
return x;
}
public static double CalculateX2(double x2, double x1)
{
double y = 20 / 0.25 * ((0.00052 * x2 * (20 - 0.25 * x2)) + 0.0075 * x1 * (10 - 0.25 * x1));
return y;
}
static void Main(string[] args)
{
string writePath = #"C:\Users\evluc\Desktop\cord.txt";
double X = -5;
double Y = -5;
int pointer = 1;
double[,] coordinates = new double[10001, 2];
coordinates[0, 0] = X;
coordinates[0, 1] = Y;
for (int i = 0; i < 5000; i++)
{
//double XTemp = CalculateX1(X, Y);
//double YTemp = CalculateX2(Y, X);
//X = CalculateX1(coordinates[pointer - 1, 0], coordinates[pointer - 1, 1]);
//Y = CalculateX2(coordinates[pointer - 1, 1], coordinates[pointer - 1, 0]);
coordinates[pointer, 0] = CalculateX1(coordinates[pointer - 1, 0], coordinates[pointer - 1, 1]);
coordinates[pointer, 1] = CalculateX2(coordinates[pointer - 1, 1], coordinates[pointer - 1, 0]);
pointer++;
if (Math.Abs(coordinates[pointer, 0]) > 1000 || Math.Abs(coordinates[pointer, 1]) > 1000)
{
Console.WriteLine("infinity");
Console.ReadKey();
}
}
for (int i = 0; i < 5000; i++)
{
Console.WriteLine("X = " + coordinates[i, 0] + "," + "Y = " + coordinates[i, 1] + "; ");
}
}
I think whatever you use to display/inspect the value cannot print ∞.
double d = double.MinValue;
d *= 2;
Console.WriteLine($"{d}: IsInfinity: {double.IsNegativeInfinity(d)}");
-∞: IsInfinity: True
Stopping at infinity
Here's a loop that stops at infinity:
double d = 2;
var i = 1;
while(!double.IsInfinity(d))
{
d = i*d*d;
i = -i;
}
Console.WriteLine(d);
-∞
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
my first question in stackoverflow...so pls inform me, if i violate the forum rules
i try to analyze the audio .wav data (basically a sinusoid with/without Noise) in FFT & draw the result as a Freq. Domain graph using C#. I need to analyze the sine wave & find whether any noise is present or not for 10 to 20seconds audio data.
Sine wave was generated using Audacity with the following properties.
1KHz Sine Tone .wav data for 15 to 20s.
16Bits per sample
44100Hz
Mono Channel
Here is the code part to separate the Audio data from the Header data.
// --- Open & Read .wav File from the Path
System.IO.FileStream WaveFile = System.IO.File.OpenRead(waveFilePath);
System.IO.BinaryReader br = new System.IO.BinaryReader(WaveFile);
// Convert the length of the file into Byte value.
waveLength = WaveFile.Length;
wave = new byte[waveLength];
// --- Subtract the .wav File Header Info (First 44 Bytes) to get the real Audio Data. Source -> http://www.topherlee.com/software/pcm-tut-wavformat.html
wavenew = new byte[(waveLength - 44)];
for (long i = 0; i < waveLength; i++)
{
wave[i] = br.ReadByte();
//Get only the Audio Data byte values
if (i >= 44)
{
wavenew[i - 44] = wave[i];
}
}
// Bits per Sample(whether 8 Bit or 16 Bit.)- Header Information35, 36 is for Bits per Sample.
bitsPerSample = BitConverter.ToInt16(wave, 34); //16Bit
//Number of Channels - Header Information 23, 24 is for No of Channels. (Mono or Stereo)
noOfChannels = BitConverter.ToInt16(wave, 22); //Mono
// Calculate the over all Audio Data length, here for FFT only values of exponential 2 can be given. So take 2 power 17 = 131072 for this calculation. Remaining Bytes will be neglected.
// Divide by 4 since every audio data contains 4 bytes. (Mono,16 Bit or Stereo,8 bit - 4 Bytes. Mono, 8 bit - 2 Bytes)
dataLength = (131116-44)/4; // /4;
data = new double[dataLength];
//SampleRate - Header Information 25 to 28 (4 Bytes) are for SampleRates
SampleRate = BitConverter.ToInt32(wave, 24); // 44100;
// The every 4 Bytes contain the data of Sinus wave.
for (int i = 0; i < dataLength; i++)
{
data[i] = BitConverter.ToInt32(wavenew, (1 + i) * 4);
}
Here are example raw Audio data after conversion.
890381306
1403864333
1804165263
2058843210
2147319456
2063433407
1812231337
1414947118
903955929
320087260
-289603352
-875963166
-1391936590
-1795514361
-2054321130
-2147384959
For FFT, I use http://www.lomont.org/Software/Misc/FFT/LomontFFT.html as a reference, which returns a Double -Real & Imag Value.
public void RealFFT(double[] data, bool forward)
{
var n = data.Length; // # of real inputs, 1/2 the complex length
// checks n is a power of 2 in 2's complement format
if ((n & (n - 1)) != 0)
throw new ArgumentException(
"data length " + n + " in FFT is not a power of 2"
);
var sign = -1.0; // assume inverse FFT, this controls how algebra below works
if (forward)
{ // do packed FFT. This can be changed to FFT to save memory
TableFFT(data, true);
sign = 1.0;
// scaling - divide by scaling for N/2, then mult by scaling for N
if (A != 1)
{
var scale = Math.Pow(2.0, (A - 1) / 2.0);
for (var i = 0; i < data.Length; ++i)
data[i] *= scale;
}
}
var theta = B * sign * 2 * Math.PI / n;
var wpr = Math.Cos(theta);
var wpi = Math.Sin(theta);
var wjr = wpr;
var wji = wpi;
for (var j = 1; j <= n/4; ++j)
{
var k = n / 2 - j;
var tkr = data[2 * k]; // real and imaginary parts of t_k = t_(n/2 - j)
var tki = data[2 * k + 1];
var tjr = data[2 * j]; // real and imaginary parts of t_j
var tji = data[2 * j + 1];
var a = (tjr - tkr) * wji;
var b = (tji + tki) * wjr;
var c = (tjr - tkr) * wjr;
var d = (tji + tki) * wji;
var e = (tjr + tkr);
var f = (tji - tki);
// compute entry y[j]
data[2 * j] = 0.5 * (e + sign * (a + b));
data[2 * j + 1] = 0.5 * (f + sign * (d - c));
// compute entry y[k]
data[2 * k] = 0.5 * (e - sign * (b + a));
data[2 * k + 1] = 0.5 * (sign * (d - c) - f);
var temp = wjr;
// todo - allow more accurate version here? make option?
wjr = wjr * wpr - wji * wpi;
wji = temp * wpi + wji * wpr;
}
if (forward)
{
// compute final y0 and y_{N/2}, store in data[0], data[1]
var temp = data[0];
data[0] += data[1];
data[1] = temp - data[1];
}
else
{
var temp = data[0]; // unpack the y0 and y_{N/2}, then invert FFT
data[0] = 0.5 * (temp + data[1]);
data[1] = 0.5 * (temp - data[1]);
// do packed inverse (table based) FFT. This can be changed to regular inverse FFT to save memory
TableFFT(data, false);
// scaling - divide by scaling for N, then mult by scaling for N/2
//if (A != -1) // todo - off by factor of 2? this works, but something seems weird
{
var scale = Math.Pow(2.0, -(A + 1) / 2.0)*2;
for (var i = 0; i < data.Length; ++i)
data[i] *= scale;
}
}
} void Scale(double[] data, int n, bool forward)
{
// forward scaling if needed
if ((forward) && (A != 1))
{
var scale = Math.Pow(n, (A - 1) / 2.0);
for (var i = 0; i < data.Length; ++i)
data[i] *= scale;
}
// inverse scaling if needed
if ((!forward) && (A != -1))
{
var scale = Math.Pow(n, -(A + 1) / 2.0);
for (var i = 0; i < data.Length; ++i)
data[i] *= scale;
}
}
public void TableFFT(double[] data, bool forward)
{
var n = data.Length;
// checks n is a power of 2 in 2's complement format
if ((n & (n - 1)) != 0)
throw new ArgumentException(
"data length " + n + " in FFT is not a power of 2"
);
n /= 2; // n is the number of samples
Reverse(data, n); // bit index data reversal
// make table if needed
if ((cosTable == null) || (cosTable.Length != n))
Initialize(n);
// do transform: so single point transforms, then doubles, etc.
double sign = forward ? B : -B;
var mmax = 1;
var tptr = 0;
while (n > mmax)
{
var istep = 2 * mmax;
for (var m = 0; m < istep; m += 2)
{
var wr = cosTable[tptr];
var wi = sign * sinTable[tptr++];
for (var k = m; k < 2 * n; k += 2 * istep)
{
var j = k + istep;
var tempr = wr * data[j] - wi * data[j + 1];
var tempi = wi * data[j] + wr * data[j + 1];
data[j] = data[k] - tempr;
data[j + 1] = data[k + 1] - tempi;
data[k] = data[k] + tempr;
data[k + 1] = data[k + 1] + tempi;
}
}
mmax = istep;
}
// perform data scaling as needed
Scale(data, n, forward);
}
Amplitude is derived from the received Real & Imag. value as below
//Converting RealFFT return value in to an amplitude for Graph
(SqurRoot of Real*Real + Imag * Imag)
realPart = new double[(dataLength / 2)];
imagPart = new double[(dataLength / 2)];
dataNew = new double[(dataLength / 2)];
for (int i = 0; i < dataNew.Length; i++)
{
if (i == 0) //Ignore the first two values, since it contain the special values. Then calculate the magnitude for real & imaginary part.
{
}
else
{
realPart[i] = data[(i * 2)] * data[(i * 2)];
imagPart[i] = data[((i * 2) + 1)] * data[((i * 2) + 1)];
dataNew[i] = Math.Sqrt(realPart[i] + imagPart[i]);
}
}
// Get these values for Y Axis as Amplitude
Values.Add(dataNew);
int N = dataNew.Length;
double[] frequencies = new double[N];
for (int i = 0; i < N; i++ )
{
if (i < (N / 2))
{
frequencies[i] = i * SampleRate / N;
}
else if (i >= (N / 2))
{
frequencies[i] = (N - i) * SampleRate / N;
}
//frequencies[i] = (i / N); //*10;
}
// Get the Frequency values for X Axis
Values.Add(frequencies);
Processed Amplitude values are looking like..
0
9030724,08220743
78204971,4566076
11562334,8871099
10855402,9273669
9213306,99124749
39816810,42806
9154491,10446211
10747893,2800474
9744695,14696198
140738122,900694
Derived Frequency from the sample rate are as follows
0
2
5
8
10
13
16
18
21
24
26
29
Finally the graph does not show the correct Freq range & peaks are observed through out the chart, even though the .wav file is a pure sine wave & does not contain any noise. (I´m not able to attach the graph image due to missing reputation, but i´m ready to post it.)
As per Sinus Tone, there should be only one peak around 1KHz, but I´m seeing again sinus like signal. I´ve checked with the different frequencies, but the result does not match with the expectation.
I could not clearly figure out where I´m doing the mistake, whether
Processing Audio Data (Splitting 4 Bytes after Header Info to Double)
Processing data within FFT
or Amplitude/Freq Graph calculation.
I´m ready to provide additional information, if required & any help would be appreciated.
The following code snippet, with width=2,height=2
int maxI = width + height;
for (int i = 1; i <= maxI; i++) {
int startJ = Math.Max(0, i - width);
int maxJ = Math.Min(i, height);
for (int j = startJ; j <= maxJ; j++) {
int x = i - j;
int y = j;
DoSomething(x,y);}}
Will call DoSomething with the following x,y pairs:
1: X=1,Y=0
2: X=0,Y=1 (Diagram: 0,0
3: X=2,Y=0 at bottom left)
4: X=1,Y=1 5 7 8
5: X=0,Y=2 2 4 6
6: X=2,Y=1 # 1 3
7: X=1,Y=2
8: X=2,Y=2
This is the desired result; to iterate a rectangle starting from 0,0 but expanding diagonally rather than (the much more popular) [y*width+x]. However, I'm baffled by the maxI=width+height and x=i-j calculations. How does this conversion work?
The thing to realize here is that x + y is a constant for each cell in a particular diagonal. For example, cells 3, 4, and 5 have coordinates {2, 0}; {1, 1}; {0, 2}. Notice that each of those add up to 2.
So maxI is really the maximum value of one of these sums. Since {width, height} is the top right, the sum for that diagonal is width + height. So that's where that comes from.
The i - j part comes about because it's basically solving the above equation. Each value of i is the sum of the coordinates. j is chosen to be the y-coordinate of a cell within that diagonal. Since we know x + y = i and that y = j, we get that x + j = i or x = i - j.
This can be also explained by geometric transformations:
1) Translation, so the rectangle's center is in origin:
x' = x - width/2
bounds: [-width/2,width/2)
y' = y - height/2
bounds: [-height/2,height/2)
2) Rotation by 45 degrees:
x'' = x'cos(45) - y'sin(45) = (sqrt(2)/2)x' - (sqrt(2)/2)y'
y'' = x'sin(45) + y'cos(45) = (sqrt(2)/2)x' + (sqrt(2)/2)y'
3) Scaling by sqrt(2)/2:
x''' = x' - y' = x - width/2 - y + height/2
bounds: [-width/2-height/2,width/2+height/2)
y''' = x' + y' = x - width/2 + y - height/2
bounds: [-width/2-height/2,width/2+height/2)
4) Translating back only on x axis:
x'''' = x''' + width/2 = x - y + height/2
bounds: [-height/2,width/2+height/2)
y'''' = y'''
bounds: [-width/2-height/2,width/2+height/2)
5) Introducing parametric variables:
i = y'''' + width/2 + height/2
bounds: [0,width+height)
j = x'''' + y'''' - width/2 - height/2
bounds: [-width-3*height/2,width/2+height/2)
For this transformation you get that:
x = i - j
y = j
And it will iterate point by point through diagonals going from bottom-right to top-left corner of the screen. Max and Min in the code you presented bound the result to a subset of these diagonals, representing a rectangle.
I'm trying to generate the mipmap of an image. The pixels are stored as a byte[] and the format is {r,g,b,a,r,g,b,a,r,g,b,a ... }
What this is trying to do is get each group of four pixels in the image and find the average of those four pixels, then put that into a new image.
The result of creating all the mipmaps for a sample texture are here: http://imgur.com/KdEEzAw
If there is a way to create the mipmaps without using my own algorithm, and without directx or anything (i'm not using the mipmaps for rendering, i'm saving them to a file) that would be good
public static byte[] mipmap(byte[] inPixels, int width, int height)
{
// add one to width and height incase they are 1
byte[] outPixels = new byte[((width + 1) / 2) * ((height + 1) / 2) * 4];
for (int y = 0; y < height; y += 2)
{
for (int x = 0; x < width; x += 2)
{
// get the four red values
int[] r = new int[4];
r[0] = (int)inPixels[x + y * width + 0]; // top left
r[1] = (int)inPixels[(x + 1) + y * width + 0]; // top right
r[2] = (int)inPixels[(x + 1) + (y + 1) * width + 0]; // bottom right
r[3] = (int)inPixels[x + (y + 1) * width + 0]; // bottom left
// get the four green values
int[] g = new int[4];
g[0] = (int)inPixels[x + y * width + 1]; // top left
g[1] = (int)inPixels[(x + 1) + y * width + 1]; // top right
g[2] = (int)inPixels[(x + 1) + (y + 1) * width + 1]; // bottom right
g[3] = (int)inPixels[x + (y + 1) * width + 1]; // bottom left
// get the four blue values
int[] b = new int[4];
b[0] = (int)inPixels[x + y * width + 2]; // top left
b[1] = (int)inPixels[(x + 1) + y * width + 2]; // top right
b[2] = (int)inPixels[(x + 1) + (y + 1) * width + 2]; // bottom right
b[3] = (int)inPixels[x + (y + 1) * width + 2]; // bottom left
// get the four alpha values
int[] a = new int[4];
a[0] = (int)inPixels[x + y * width + 3]; // top left
a[1] = (int)inPixels[(x + 1) + y * width + 3]; // top right
a[2] = (int)inPixels[(x + 1) + (y + 1) * width + 3]; // bottom right
a[3] = (int)inPixels[x + (y + 1) * width + 3]; // bottom left
// the index in the new image, we divide by 2 because the image is half the size of the original image
int index = (x + y * width) / 2;
outPixels[index + 0] = (byte)((r[0] + r[1] + r[2] + r[3]) / 4);
outPixels[index + 1] = (byte)((g[0] + g[1] + g[2] + g[3]) / 4);
outPixels[index + 2] = (byte)((b[0] + b[1] + b[2] + b[3]) / 4);
outPixels[index + 3] = (byte)((a[0] + a[1] + a[2] + a[3]) / 4);
}
}
return outPixels;
}
I think the problem lies here:
inPixels[x + y * width + 0]
normally this runs correct when one array element is one pixel, only one element is one channel of one pixel. So each pixel starts a (x + (y * width)) * 4 so it should be something like this:
inPixels[((x + y * width) * 4) + 0]
I wrote some code for optimalization maybe you get some extra ideas, but i did not test it:
public static byte[] mipmap(byte[] inPixels, int width, int height)
{
// add one to width and height incase they are 0
byte[] outPixels = new byte[((width / 2) * (height / 2)) * 4];
// the offsets of the neighbor pixels (with *4 for the channel)
// this will automatically select a channel of a pixel one line down.
int[] neighborOffsets = new int[] { 0 * 4, 1 * 4, width * 4, (width + 1) * 4 };
// an 'offset for output buffer'
int outputOffset = 0;
// an 'offset for input buffer'
int inputOffset = 0;
for (int y = 0; y < height / 2; y++)
{
for (int x = 0; x < width / 2; x++)
{
// calculate the average of each channel
for (int channelIndex = 0; channelIndex < 4; channelIndex++)
{
int totalValue = 0;
for (int offset = 0; offset < 4; offset++)
totalValue = (int)inPixels[inputOffset + neighborOffsets[offset] + channelIndex];
// write it to the ouput buffer and increase the offset.
outPixels[outputOffset++] = (byte)(totalValue / 4);
}
// set the input offset on the next pixel. The next pixel is current + 2.
inputOffset += 2 * 4; // *4 for the channelcount (*4 will be optimized by the compiler)
}
inputOffset += width * 4; // skip an extra line. *4 for the channelcount (*4 will be optimized by the compiler)
}
return outPixels;
}
There maybe some little mistakes in it, but it probably run 4 times as fast. Try to avoid redundancy on multiplications.