Im doing a FastFourier Transform. So the return values are in the range 0-255 with the higher the volume the bigger the value
Now I have different shapes of various colors. Depending on the volume at the same point in the sound file the FFT can return e.g 1 (low volume) or e.g. 155 (high volume)
I need to brighten or (return to original color if 0 returned) the FillColor of the shape depending on the return value (0-255)
So how do I:
a) Scale the return value in accordance to the sound volume (volume 0-100)
b) brighten the color (e.g. Red by the scaled return value)
Note. Its important that the color is brightened if value > 0
An edit for those who think I DEMAND help.
private void _t_Tick(object sender, EventArgs e)
{
int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT8192); //get ch.annel fft data
if (ret < -1) return;
int x, y;
int b0 = 0;
//computes the spectrum data, the code is taken from a bass_wasapi sample.
for (x = 0; x < _lines; x++)
{
float peak = 0;
int b1 = (int)Math.Pow(2, x * 10.0 / (_lines - 1));
if (b1 > 1023) b1 = 1023;
if (b1 <= b0) b1 = b0 + 1;
for (; b0 < b1; b0++)
{
if (peak < _fft[1 + b0]) peak = _fft[1 + b0];
}
y = (int)(Math.Sqrt(peak) * 3 * 255 - 4);
if (y > 255) y = 255;
if (y < 0) y = 0;
_spectrumdata.Add((byte)y);
//Console.Write("{0, 3} ", y);
}
if (DisplayEnable) _spectrum.Set(_spectrumdata);
for (int i = 0; i < _spectrumdata.ToArray().Length; i++)
{
try
{
//if (_spectrumdata[i] > mth)
//{
// _shapes.ToArray()[i].FillColor = _colors.ToArray()[i];// Class1.Increase(_colors.ToArray()[i], _spectrumdata[i]);
//}
//else
//{
// _shapes.ToArray()[i].FillColor = Color.Black; //Class1.Increase(Color.Black, _spectrumdata[i]);
//}
//double d = Math.Round(((float)_spectrumdata[i]) / 255 , 2);
double[] d = GetScaling(_spectrumdata.ToArray(), 0,1);
if (_spectrumdata[i] > mth)
{
_shapes.ToArray()[i].FillColor = ControlPaint.Light(_colors.ToArray()[i], Convert.ToSingle(d[i]));
}
else
{
_shapes.ToArray()[i].FillColor = _colors.ToArray()[i]; ;// Color.Black; //Class1.Increase(Color.Black, _spectrumdata[i]);
}
}
catch (Exception)
{
}
try
{
_chart.Series["wave"].Points.RemoveAt(0);
}
catch (Exception)
{
}
}
_spectrumdata.Clear();
int level = BassWasapi.BASS_WASAPI_GetLevel();
_l.Value = (Utils.LowWord32(level));
_r.Value = (Utils.HighWord32(level));
if (level == _lastlevel && level != 0) _hanctr++;
_lastlevel = level;
//Required, because some programs hang the output. If the output hangs for a 75ms
//this piece of code re initializes the output so it doesn't make a gliched sound for long.
if (_hanctr > 3)
{
_hanctr = 0;
_l.Value = (0);
_r.Value = (0);
Free();
Bass.BASS_Init(0, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero);
_initialized = false;
Enable = true;
}
}
I have absolutely no clue what the hell you're talking about, but if you're just trying to take a number 1-155 and amplify it to 1-255, try multiplying.
Some simple math (155x = 255) has revealed that x, the number you have to multiply by, is equal to 51/31 or ~1.64516129.
So, what you would do is multiply your original brightness, lets say 35, by 1.64516129.
35 * 1.64516129 = 57.58064.
You can use the Math class to round the number to the nearest integer, which you can then use as your new brightness value.
Related
I have a temperature sensor returning 2 bytes.
The temperature is defined as follows :
What is the best way in C# to convert these 2 byte to a float ?
My sollution is the following, but I don't like the power of 2 and the for loop :
static void Main(string[] args)
{
byte[] sensorData = new byte[] { 0b11000010, 0b10000001 }; //(-1) * (2^(6) + 2^(1) + 2^(-1) + 2^(-8)) = -66.50390625
Console.WriteLine(ByteArrayToTemp(sensorData));
}
static double ByteArrayToTemp(byte[] data)
{
// Convert byte array to short to be able to shift it
if (BitConverter.IsLittleEndian)
Array.Reverse(data);
Int16 dataInt16 = BitConverter.ToInt16(data, 0);
double temp = 0;
for (int i = 0; i < 15; i++)
{
//We take the LSB of the data and multiply it by the corresponding second power (from -8 to 6)
//Then we shift the data for the next loop
temp += (dataInt16 & 0x01) * Math.Pow(2, -8 + i);
dataInt16 >>= 1;
}
if ((dataInt16 & 0x01) == 1) temp *= -1; //Sign bit
return temp;
}
This might be slightly more efficient, but I can't see it making much difference:
static double ByteArrayToTemp(byte[] data)
{
if (BitConverter.IsLittleEndian)
Array.Reverse(data);
ushort bits = BitConverter.ToUInt16(data, 0);
double scale = 1 << 6;
double result = 0;
for (int i = 0, bit = 1 << 14; i < 15; ++i, bit >>= 1, scale /= 2)
{
if ((bits & bit) != 0)
result += scale;
}
if ((bits & 0x8000) != 0)
result = -result;
return result;
}
You're not going to be able to avoid a loop when calculating this.
I am working on an edge points extraction algorithm.
I have a List of points representing a blob (a group of connected pixels) and I want to extract edge points.
I have an example algorithm below, but I am wondering if there is a faster way.
I am using class for BlobPoint, because there is more to it than shown in the example below.
BlobPoint index value represent index value in the original image (image is 1D array of pixels, hence required width information).
This algorithm is build on idea that if a pixel on right or bottom or left or top does not exist in the list, then this point is an edge point.
The list will usually contain between 20 000 to 1 000 000 elements.
yr and yl are added for clarity.
public static List<BlobPoint> GetEdgePoints(this List<BlobPoint> points, int width)
{
int length = points.Count;
List<BlobPoint> temp = new List<BlobPoint>();
for (int i = 0; i < length; i++)
{
BlobPoint point = points[i];
int x = point.X;
int y = point.Y;
int xr = x + 1;
int yr = y;
int xb = x - width;
int yb = y - 1;
int xl = x - 1;
int yl = y;
int xt = x + width;
int yt = y + 1;
if (!points.Any(p => p.X == xb && p.Y == yb) || !points.Any(p => p.X == xl && p.Y == yl) || !points.Any(p => p.X == xr && p.Y == yr) || !points.Any(p => p.X == xt && p.Y == yt))
{
temp.Add(point);
}
}
return temp;
}
public class BlobPoint
{
public int X = 0;
public int Y = 0;
public int Index = 0;
public BlobPoint(int x, int y, int index)
{
X = x;
Y = y;
Index = index;
}
}
My solution:
Ok, I have done some testing and the method above is way too slow for my needs.
I will leave question as this might be of use to someone who looks for faster iteration method.
This is a solution I came up with, but it is still a bit slow:
public static Dictionary<int, List<BlobPoint>> GetEdgePoints(BlobPoint[] points, int[] labels, int image_width, int image_height)
{
int length = labels.Length;
if (image_height * image_width != length) throw new ArgumentException("image_width x image_height does not match labels.Length");
if (length == 0) throw new ArgumentException("label array cannot be empty!");
if (points.Length != length) throw new ArgumentException("points array length cannot be different from labels array length!");
var dict = new Dictionary<int, List<BlobPoint>>();
for (int i = 0; i < length; i++)
{
int label = labels[i];
if (label <= 0) continue;
BlobPoint point = points[i];
int x = point.X;
int y = point.Y;
int width_offset = image_width - 1;
int height_offset = image_height - 1;
if (x > 0 && x < width_offset && y > 0 && y < height_offset)
{
if (labels[i + 1] == label && labels[i - 1] == label && labels[i + image_width] == label && labels[i - image_width] == label)
{
continue;
}
}
if (dict.ContainsKey(label))
dict[label].Add(point);
else
dict.Add(label, new List<BlobPoint>() { point });
}
return dict;
}
Personally, I'd use a two-dimensional Boolean array representing the image for this, in which the indices for the points you have are set to true. In exchange for some memory, and a single loop over the points in advance, this allows lightning-fast checks of whether a point is inside the list, removing all internal iterations for lookups on the points list. There is not a single .Contains or .Any or .All performed here. Just two loops over the main list, and eight very simple checks inside the second loop.
public static List<BlobPoint> GetEdgePoints(this List<BlobPoint> points, Int32 imageWidth, Int32 imageHeight)
{
Boolean[,] pointInList = new Boolean[imageHeight, imageWidth];
foreach (BlobPoint p in points)
pointInList[p.Y, p.X] = true;
List<BlobPoint> edgePoints = new List<BlobPoint>();
Int32 lastX = imageWidth - 1;
Int32 lastY = imageHeight - 1;
foreach (BlobPoint p in points)
{
Int32 x = p.X;
Int32 y = p.Y;
// Image edge is obviously a blob edge too.
// Coordinates checks are completely safe after the edge checks.
if (x == 0 || y == 0 || x == lastX || y == lastY
|| !pointInList[y - 1, x]
|| !pointInList[y, x - 1]
|| !pointInList[y, x + 1]
|| !pointInList[y + 1, x])
edgePoints.Add(p);
}
return edgePoints;
}
This technically works without the image width and height, but then you need to do another loop in advance to get the maximum x and y present in your points, so you can make a Boolean[,] array that can contain all coordinates. If you have that image data, though, it's obviously a lot more efficient to just use it.
Not sure why you bother with the BlobPoint class over the standard Point struct, though. The index in the original array is just p.Y * stride + p.X anyway.
I'm trying to randomly generate blocks on a flat map and make it so that they don't overlap each other.
I have made a matrix (c# array) of the size of the map (500x500), the blocks have a scale between 1 and 5.
The code works but if a generated block overlaps another one, it is destroyed and not regenerated somewhere else.
Only around 80 of the 1000 blocks I try to generate don't overlap another block.
Here is a picture of the map with around 80 blocks generated, the green squares are blocks
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
bool elementFound = false;
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el;
// Randomly generate block size and position
int size = Random.Range(minScale, maxScale + 1);
int x = Random.Range(0, mapSizex + 1 - size);
int y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
if (elementFound)
continue;
else {
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
}
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
}
}
I thought of 3 possible fixes
I should set the size of the block depending of the place it has.
I should use another randomization algorithm.
I'm not doing this right.
What do you think is the best idea ?
UPDATE
I got the code working much better. I now try to instantiate the blocks multiple times if needed (maximum 5 for the moment) and I fixed the bugs. If there are already many elements on the map, they will not always be instantiated and that's what I wanted, I just have to find the right amount of times it will try to instantiate the block.
I tried instantiating 1280 elements on a 500x500 map. It takes only about 1.5 second and it instantiated 1278/1280 blocks (99.843%).
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
bool elementFound = false;
int cnt = 0;
// Generate every block
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el = null;
// Randomly generate block size and position
int size, x, y, tryCnt = 0;
// Try maximum 5 times to generate the block
do {
elementFound = false;
// Randomly set block size and position
size = Random.Range(minScale, maxScale + 1);
x = Random.Range(0, mapSizex + 1 - size);
y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
tryCnt++;
} while (elementFound && tryCnt < 5);
if (tryCnt >= 5 && elementFound) continue;
// Instantiate the block
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
cnt++;
}
print("Instantiated " + cnt + "/" + ratio * generationDefault);
}
This is incredibly difficult to do well.
Here's a quick solution you'll maybe like ... depending on your scene.
actualWidth = 500 //or whatever. assume here is square
// your blocks are up to 5 size
chunkWidth = actualWidth / 5
// it goes without saying, everything here is an int
kChunks = chunkWidth*chunkWidth
List<int> shuf = Enumerable.Range(1,kChunks).OrderBy(r=>Random.value).ToList();
howManyWanted = 1000
shuf = shuf.Take(howManyWanted)
foreach( i in shuf )
x = i % actualWidth
y = i / actualWidth
make block at x y
put block in list allBlocks
HOWEVER ............
...... you'll see that this looks kind of "regular", so do this:
Just randomly perturb all the blocks. Remember, video game programming is about clever tricks!
Ideally, you have to start from the middle and work your way out; in any event you can't just do them in a line. Shuffling is OK. So, do this ..
harmonic = 3 //for example. TRY DIFFERENT VALUES
function rh = Random.Range(1,harmonic) (that's 1 not 0)
function rhPosNeg
n = rh
n = either +n or -n
return n
function onePerturbation
{
allBlocks = allBlocks.OrderBy(r => Random.value) //essential
foreach b in allBlocks
newPotentialPosition = Vector2(rhPosNeg,rhPosNeg)
possible = your function to check if it is possible
to have a block at newPotentialPosition,
however be careful not to check "yourself"
if possible, move block to newPotentialPosition
}
The simplest approach is just run onePerturbation, say, three times. Have a look at it between each run. Also try different values of the harmonic tuning factor.
There are many ways to perturb fields of differently-sized blocks, above is a KISS solution that hopefully looks good for your situation.
Coding note...
How to get sets of unique random numbers.
Just to explain this line of code...
List<int> shuf = Enumerable.Range(1,kChunks).OrderBy(r=>Random.value).ToList();
If you are new to coding: say you want to do this: "get a hundred random numbers, from 1 to million, but with no repeats".
Fortunately, this is a very well known problem with a very simple solution.
The way you get numbers with no repeats, is simply shuffle all the numbers, and then take how many you want off the top.
For example, say you need a random couple of numbers from 1-10 but with no repeats.
So, here's the numbers 1-10 shuffled: 3,8,6,1,2,7,10,9,4,5
Simply take what you need off the front: so, 3, 8, 6 etc.
So to make an example let's say you want twelve numbers, no repeats, from 1 through 75. So the first problem is, you want a List with all the numbers up to 75, but shuffled. In fact you do that like this ..
List<int> shuf = Enumerable.Range(1,75).OrderBy(r=>Random.value).ToList();
So that list is 75 items long. You can check it by saying foreach(int r in shuf) Debug.Log(r);. Next in the example you only want 12 of those numbers. Fortunately there's a List call that does this:
shuf = shuf.Take(12)
So, that's it - you now have 12 numbers, no repeats, all random between 1 and 75. Again you can check with foreach(int r in shuf) Debug.Log(r);
In short, when you want "n" numbers, no repeats, between 1 and Max, all you have to so is this:
List<int> shuf = Enumerable.Range(1,Max).OrderBy(r=>Random.value).ToList();
shuf = shuf.Take(n);
et voilĂ , you can check the result with foreach(int r in shuf) Debug.Log(r);
I just explain this at length because the question is often asked "how to get random numbers that are unique". This is an "age-old" programming trick and the answer is simply that you shuffle an array of all the integers involved.
Interestingly, if you google this question ("how to get random numbers that are unique") it's one of those rare occasions where google is not much help, because: whenever this question is asked, you get a plethora of keen new programmers (who have not heard the simple trick to do it properly!!) writing out huge long complicated ideas, leading to further confusion and complication.
So that's how you make random numbers with no repeats, fortunately it is trivial.
if (elementFound) continue; will skip out this current loop iteration. You need to wrap the int x=Random..; int y=Random()..; part in a while loop with the condition being while(/* position x/y already occupued*/) { /* generate new valid point */} like this for example:
void generateElement(int ratio, int minScale, int maxScale, GameObject g) {
for (int i = 0; i < ratio * generationDefault; i++) {
GameObject el;
// Randomly generate block size and position
bool elementFound = false;
int size, x, y;
do
{
elementFound = false;
size = Random.Range(minScale, maxScale + 1);
x = Random.Range(0, mapSizex + 1 - size);
y = Random.Range(0, mapSizey + 1 - size);
// Check if there is already an element
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] != null)
elementFound = true;
} while(elementFound);
el = (GameObject)Instantiate(g, new Vector3(x + (float)size / 2, (float)size / 2, y + (float)size / 2), Quaternion.Euler(0, 0, 0));
el.transform.localScale *= size;
// Create element on map array
for (int j = x; j < x + size; j++)
for (int k = y; k < y + size; k++)
if (map[j][k] == null) {
map[j][k] = el.GetComponent<ObjectInterface>();
}
}
}
You shouldn't be getting that many collisions.
Assuming your blocks were ALL 5 units wide and you're trying to fit them into a grid of 500,500 you would have 100*100 spaces for them at minimum, which gives 10,000 spaces into which to fit 1,000 blocks.
Try playing around with this code:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
var result = PlaceNonOverlappingBlocks(1000, 5, 500, 500);
}
static List<Block> PlaceNonOverlappingBlocks(int count, int maxBlockSize, int mapX, int mapY)
{
var map = new bool[mapY, mapX];
var rng = new Random();
var result = new List<Block>(count);
int collisions = 0;
while (count > 0)
{
int size = rng.Next(1, maxBlockSize + 1);
int x = rng.Next(0, mapX - size);
int y = rng.Next(0, mapY - size);
if (fits(map, x, y, size))
{
result.Add(new Block(x, y, size));
addToMap(map, x, y, size);
--count;
}
else
{
if (++collisions> 100000)
throw new InvalidOperationException("Hell has frozen over");
}
}
// This is just for diagnostics, and can be removed.
Console.WriteLine($"There were {collisions} collisions.");
return result;
}
static void addToMap(bool[,] map, int px, int py, int size)
{
for (int x = px; x < px+size; ++x)
for (int y = py; y < py + size; ++y)
map[y, x] = true;
}
static bool fits(bool[,] map, int px, int py, int size)
{
for (int x = px; x < px + size; ++x)
for (int y = py; y < py + size; ++y)
if (map[y, x])
return false;
return true;
}
internal class Block
{
public int X { get; }
public int Y { get; }
public int Size { get; }
public Block(int x, int y, int size)
{
X = x;
Y = y;
Size = size;
}
}
}
}
Anyone know a simple algorithm to implement in C# to detect monster groups in a 2D game.
EX:
100 Range around the char there are monsters. I want to detect which monsters are within range 2 of each other, and if there is at-least 5 together, use the Area of Effect skill on that location. Otherwise use the single-target skill.
A link to an implementation would be great, C# preferably. I just get lost reading the Wikipedia articles.
EDIT:
"your question is incomplete. what do you want to do exactly? do you want to find all groups? the biggest group? any group, if there are groups, none otherwise? please be more specific." -gilad hoch
I want to find all groups within 100 units of range around the main character. The groups should be formed if there are at-least 5 or more monsters all within 2 range of each other, or maybe within 10 range from the center monster.
So the result should be probably a new List of groups or a List of potential target locations.
a very simple clustering algorithm is the k-mean algorithm. it is like
create random points
assign all points to the nearest point, and create groups
relocate the original points to the middle of the groups
do the last two steps several times.
an implementation you can find for example here, or just google for "kmean c#"
http://kunuk.wordpress.com/2011/09/20/markerclusterer-with-c-example-and-html-canvas-part-3/
I recently implemented the algorithm given in this paper by Efraty, which solves the problem by considering the intersections of circles of radius 2 centered at each given point. In simple terms, if you order the points in which two circles intersect in clockwise order, then you can do something similar to a line sweep to figure out the point in which a bomb (or AoE spell) needs to be launched to hit the most enemies. The implementation is this:
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;
#define INF 1e16
#define eps 1e-8
#define MAXN 210
#define RADIUS 2
struct point {
double x,y;
point() {}
point(double xx, double yy) : x(xx), y(yy) {}
point operator*(double ot) {
return point(x*ot, y*ot);
}
point operator+(point ot) {
return point(x+ot.x, y+ot.y);
}
point operator-(point ot) {
return point(x-ot.x, y-ot.y);
}
point operator/(double ot) {
return point(x/ot, y/ot);
}
};
struct inter {
double x,y;
bool entry;
double comp;
bool operator< (inter ot) const {
return comp < ot.comp;
}
};
double dist(point a, point b) {
double dx = a.x-b.x;
double dy = a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
int N,K;
point p[MAXN];
inter it[2*MAXN];
struct distst {
int id, dst;
bool operator<(distst ot) const {return dst<ot.dst;}
};
distst dst[200][200];
point best_point;
double calc_depth(double r, int i) {
int left_inter = 0;
point left = p[i];
left.y -= r;
best_point = left;
int tam = 0;
for (int k = 0; k < N; k++) {
int j = dst[i][k].id;
if (i==j) continue;
double d = dist(p[i], p[j]);
if (d > 2*r + eps) break;
if (fabs(d)<eps) {
left_inter++;
continue;
}
bool is_left = dist(p[j], left) < r+eps;
if (is_left) {
left_inter++;
}
double a = (d*d) / (2*d);
point diff = p[j] - p[i];
point p2 = p[i] + (diff * a) / d;
double h = sqrt(r*r - a*a);
it[tam].x = p2.x + h*( p[j].y - p[i].y ) / d;
it[tam].y = p2.y - h*( p[j].x - p[i].x ) / d;
it[tam+1].x = p2.x - h*( p[j].y - p[i].y ) / d;
it[tam+1].y = p2.y + h*( p[j].x - p[i].x ) / d;
it[tam].x -= p[i].x;
it[tam].y -= p[i].y;
it[tam+1].x -= p[i].x;
it[tam+1].y -= p[i].y;
it[tam].comp = atan2(it[tam].x, it[tam].y);
it[tam+1].comp = atan2(it[tam+1].x, it[tam+1].y);
if (it[tam] < it[tam+1]) {
it[tam].entry = true;
it[tam+1].entry = false;
}
else {
it[tam].entry = false;
it[tam+1].entry = true;
}
if (is_left) {
swap(it[tam].entry, it[tam+1].entry);
}
tam+=2;
}
int curr,best;
curr = best = left_inter;
sort(it,it+tam);
for (int j = 0; j < tam; j++) {
if (it[j].entry) curr++;
else curr--;
if (curr > best) {
best = curr;
best_point = point(it[j].x, it[j].y);
}
}
return best;
}
int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%lf %lf", &p[i].x, &p[i].y);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
dst[i][j].id = j;
dst[i][j].dst = dist(p[i],p[j]);
}
sort(dst[i],dst[i]+N);
}
int best = 0;
point target = p[0];
for (int i = 0; i < N; i++) {
int depth = calc_depth(RADIUS, i);
if (depth > best) {
best = depth;
target = best_point;
}
}
printf("A bomb at (%lf, %lf) will hit %d target(s).\n", target.x, target.y, best+1);
}
Sample usage:
2 (number of points)
0 0
3 0
A bomb at (1.500000, 1.322876) will hit 2 targets.
screenshot of debug: http://img1.uploadscreenshot.com/images/orig/12/36121481470-orig.jpg
note how x, y have values (i have no idea why x and y stopped on 69 in the for loop - x should've went up to 86 and y to 183) yet r has no value at all. (the variable doesn't exist? what?) how should I fix this?
code if you want to read:
public float[] cht(int[,] matrix)
{
float[] xyrd = new float[4];
int xthreshold, ythreshold;
float slope;
double dir;
float zone;
int[] limitsStorage = new int[3] { matrix.GetLength(0), matrix.GetLength(1), matrix.GetLength(0) / 2 - 10 };
short[,,] accumulator = new short[limitsStorage[0]+1, limitsStorage[1]+1,limitsStorage[2]+1];
for (int x = 0; x < limitsStorage[0]; x++)
{ //first dimension loop of matrix 100
for (int y = 0; y < limitsStorage[1]; y++)
{ //second dimension loop of matrix 120
if (matrix[x, y] == 225)
{//the data at the for loop location is a 1 and not 0 hit.
xthreshold = x - limitsStorage[0] / 2;
ythreshold = y - limitsStorage[1] / 2;
//forget angle, search slope: float angle = xthreshold > 0 ? ((float)Math.Atan2(xthreshold, ythreshold)) : ((float)Math.Atan2(xthreshold, ythreshold) + 180);
slope = xthreshold / ythreshold;
//initiate if loops.
dir = 180 + Math.Round(Math.Atan2(ythreshold, xthreshold) * 57.2957 / 45, 0) * 45 + 45 * (Math.Round(((Math.Atan2(ythreshold, xthreshold) * 57.2957) % 45) / 45));
if (slope > .404 || slope < -.404)
{
if (slope < 2.3558 || slope > -2.3558)
{
if (xthreshold > 0)
{
if (ythreshold > 0)
{
//+x+y zone
zone = 45 + 180;
}
else
{
//+x-y zone
zone = 180 - 45;
}
}
else
{
if (ythreshold > 0)
{
//-x+y zone
zone = 360 - 45;
}
else
{
//-x-y zone
zone = 45;
}
}
}
else if (ythreshold > 0)
{
//+y zone
zone = 360 - 90;
}
else
{
//-y zone
zone = 90;
}
}
else if (xthreshold > 0)
{
//+x zone
zone = 180;
}
else
{
//-x zone
zone = 0;
}
for (int R = 6; R < limitsStorage[2]; R++)
{ //Radius loop for scan 44
float delta = (float)((1 / R) * 57.2957);
for (float Theta = zone - 25; Theta < zone + 25; Theta += delta)
{
accumulator[(int)(((R * Math.Cos(Theta / 57.2957)) < 0 || (R * Math.Cos(Theta / 57.2957)) > limitsStorage[0]) ? 0 : R * Math.Cos(Theta / 57.2957)), (int)(((R * Math.Sin(Theta / 57.2957)) < 0 || (R * Math.Sin(Theta / 57.2957)) > limitsStorage[1]) ? 0 : R * Math.Sin(Theta / 57.2957)),R]++;
//btw, 0,0,R is always the non-center area.
}
}
}
}
}
for (int x = 1; x < limitsStorage[0]; x++)
{
for (int y = 1; y < limitsStorage[1]; y++)
{
for (int r = 6; r < limitsStorage[2]; r++)
{
if (xyrd[3] > accumulator[x, y, r])
{
xyrd[0] = x;
xyrd[1] = y;
xyrd[2] = r;
xyrd[3] = accumulator[x, y, r];
}
}
}
}
if (accPrint)
{
//do something for debugging?
accPrint = false;
}
return xyrd;
}
I just noticed that the x and y have the little lock symbol under them indicating that you have private variables named x and y in the class in which this method is executing. Those are the x and y that you are seeing in the debugger.
r is appropriately out of scope as you've exited the loop in which it is declared.
By the way, x and y are ridiculously bad member variable names, and are ridiculously bad names for for loop variables of type int, especially if they are contained in a class with member variables named x and y.
The only place you declare r is in the for statement, right? That means r goes out of scope as soon as the loop ends. So naturally if you inspect variables at he end of the function, r won't be there.
Confessing I don't know why x and y are in scope based on the comments. They could be class variables, but the asker says not. That's the only explanation I can think of, though.
The behaviour is not weird -- you actually get exactly what you expect.
Please note that the watch window can only accurately show you values that are in scope at the breakpoint.
At the highlighted breakpoint, only accumulator[x, y, r] is in scope, and you see exactly the values you expected.