Best algorithm performance in equating many values - android

i am developing an android application right now. and i got a problem with one important method in my app, because i can't make best algorithm to equate many inputs to many data.
Here's the scenario:
The method's input is a coordinates from override method onTouchEvent(), so the input will be so many when the screen is touched and the finger is moved on it.
i have to equate that so-many-coordinate to 24 values in array.
the values in array is a coordinate as well. So when the input has the same value as values in arrays, it scores a point.
here's the code that i used:
public void checkCoordinate(float x, float y){
int sensitivity = 30;
for(int z = 0; z < 24; z++){
if(x > (cxy[z][0]-sensivity) && x < (cxy[z][0]+sensivity) && y > (cxy[z][1]-sensivity) && y < (cxy[z][1]+sensivity)){
points += 1;
Log.i("CheckCoordinate", "Total Points = "+points);
}
}
i have 2 ways to equating it. one, using the algorithm above or, using 24 if to check every input. but i don't think that 2 ways is good in this case.
so i need your help if you had the same case as mine and you have solved that or you have a better or best solution please tell me.
thank you in advance. sorry if my english is bad.

With this being said, your generic idea is correct. The question is can it now be optimized somehow?
There are many methods we can potentially employ here. The trick is all in the way you arrange your data. In your current case, you are doing a center point with your sensitivity variable being your span. One could imagine the first optimization being instead of using a sensitivity that moves left right up and down from a center point, you could implement instead a top-left point with a span that only moves right and down from the top-left point. Your if statement would then become:
if(x > cxy[z][0] && x < (cxy[z][0]+sensivity) && y > cxy[z][1] && y < (cxy[z][1]+sensivity))
So what does this do for you:
This above optimization allows you to hold the same overall amount of data but get rid of 2 math operations per check. Considering that your input parameters are both floating points, this can save quite a bit of time.
If you are doing all pixel based operations, then that brings me to the next optimization. Do ALL calculation using integers instead of floating point, this will also heavily speed up your overall algorithm time.
a further optimization could now be, if you are willing to spend more RAM for better performance, you could instead of having 1 point per region, you could have a top-left and a bottom-right point for each region. This would make your if statement look something like the following:
if(x > tlxy[z][0] && x < brxy[z][0] && y > tlxy[z][1] && y < brxy[z][1])
where tlxy is the array of top-left points, brxy is the array of bottom-right points
and z is still the "region" you are checking against
How does this aid:
As you can see in the above if statement, this now has absolutely no explicit math operations. To support this algorithm, you need to be willing to spend 2 times the memory as the array cxy originally was.
Now within your loop, you are going through ALL 24 region points. If you KNOW FOR CERTAIN that none of your regions overlap, then a point can truly only fall in 1 region at a time. You can save some time on most x y input points by breaking out of the for loop at the point you also increment points. That would look as follows:
public void checkCoordinate(float x, float y){
for(int z = 0; z < 24; z++){
if(x > tlxy[z][0] && x < brxy[z][0] && y > tlxy[z][1] && y < brxy[z][1]){
points += 1;
break;
}
}
}
The above will ONLY WORK IFF you know for certain there are no overlapping regions (not even edges.
On final optimization I can see might have potential. Depending on what your regions look like, you could pre-separate all regions into quadrants. This way you can test the x point to be on the left or right hand of the screen, then test the y point to be in the top or bottom. If your regions distribution is fairly even, this could have the potential to cut your test time down by 4 as you would not only need to test the regions within a quadrant (if the given statistical distribution is what I said). In the worst case, all regions lie in a single quadrant and all points you test are in that quadrant in which case the problem from a complexity standpoint is no worse than what it was before. It simply adds a setup test on your input x and y.
I hope this gives you enough info to at least get started on your way!!!

For 24 values, this might be an overkill, but you might also want to consider using a plain-array hash table (with open addressing collision resolution):
For simplicity, let's say you use the y value to get the jump position (if regions are well separated vertically, this should decrease the number of checks). Presuming that your screen resolution is 600x800, you can divide y by 60 to get ~13 slots. If you are using a 8-bit table, that equals to ~18 items per slot (round(800/60)=13, round(255/13)=18).
To speed up calculations, you should keep everything round and simple, so you can get the slot number using:
int yi = (int)y;
// this is your "hash function". depending on your actual data,
// you might want to modify it to get a lesser chance of collisions
byte slot = (byte)((yi / 60) * 18);
Now that you have the slot index, simply jump to the hash table and check until there are no more items to check:
rectangle r;
int yi = (int)y;
for (byte slot=(byte)(yi / 26); slot < 256; slot++)
{
r = hashtable[slot];
// is this an empty slot?
if (r.brxy == 0)
break;
// perform exact check
if (r.left < x && x < r.right &&
r.top < y && y < r.bottom)
break;
}
Hash table needs to be created during init in a similar way: for each of your 24 regions, calculate its hash (slot) index. If the position in the hash table is occupied, simply increase by 1 until you find an empty spot. NOTE: will you will have to add each region to all overlapping slots. A simplest way would be to add it to slots s, s-1 and s+1.
Your loop currently does 12 lookups on average, while a hash-based approach performs a single hash calculation and should require only two or three lookups on average (hash tables are said to have O(1) complexity on average, presuming a good hash function).
Example
Your hashtable should ideally look something like:
hashtable[0]: rectangle(0, 0, 60, 60);
hashtable[1]: rectangle(20, 20, 80, 80);
hashtable[2]: (empty)
hashtable[3]: (empty)
...
// next slot starts at [18]
hashtable[18]: rectangle(20, 20, 80, 80); // this region is in slots 0 and 1
hashtable[19]: rectangle(30, 70, 90, 130);
hashtable[20]: rectangle(400, 70, 460, 130);
hashtable[21]: (empty)
...
So, if your touch point is (430, 100), calculation will continue as follows:
a) slot = (byte)((100/60) * 18) = 18;
b) check hashtable[18], overlapping? no
c) check hashtable[19], overlapping? no
c) check hashtable[20], overlapping? yes, found after 3 checks
Performance only depends on the chosen hash-function:
If you have many items with similar x coordinates, you might get many collisions in some slots: that is why it's important to choose a good hash function. If regions are fixed, you can even create a perfect hash.

Related

MPAndroidChart show specified range of XValues even when there is no corresponding YValue?

The Problem I am having is that I have charts which should always show a fixed range of XValues let's say all 24 hours in a day, but the Chart is only showing XValues up to and starting from the point of the first and last YValue, that is if I have two Y events, let's say 2am and 3pm, instead of showing the whole 24 hours, it will start at 2am and end at 3pm.
I think this has something to do with the new way to handle XValues via IAxisValueFormatter, since this used to work fine when we could add both X and Y values to a ChartData.
One hack to workaround this I found is to add empty YValues to first and last hour in my case 0 values, but this brings another issue that no matter what I set the minimum in LeftAxis it starts showing negative label values (starts in -15 instead of 0).
Is there an official way to do this? I have researched quite a bit about this and I am thinking on going back to a previous version of the library where I could just use the old way.
Edit: Just to clarify the problem doesn't have anything to do with the labels, but with the start and end of the Chart in X, it is discarding the range of X which doesn't have any YValues which I understand makes sense but it makes the results look ugly in certain cases.
You can use the setLabelCount() method to force the axis to draw labels according to the count you specify
According to the documentation:
setLabelCount(int count, boolean force)
#param count: the number of y-axis labels that should be displayed
#param force if enabled, the set label count will be forced, meaning that the exact specified count of labels will be drawn and evenly distributed alongside the axis - this might cause labels to have uneven values
And the setLabelCount method is defined below
public void setLabelCount(int count) {
if (count > 25)
count = 25;
if (count < 2)
count = 2;
mLabelCount = count;
mForceLabels = false;
}
You can use setLabelCount() with setAxisMaximum() and setAxisMinimum()
For example:
axis.setLabelCount(24, true);
axis.setAxisMaximum(24f);
axis.setAxisMinimum(0f);
This will draw values from 0 - 24 regardless of Y-Axis values

calabash-android how to create loops or iterate something until an exit condition?

I'm trying a seat selection process for a bus. I have a seat layout with some seats booked ans some not booked. I need to select an unbooked seat. I need to create a loop by tapping random coordinates on the screen till i am able to tap on a unbooked seat. how can this be done using calabash.
This thread is a bit old. But anyways here goes something along the lines of what you are looking for.
You want to touch a certain set of coordinates on the screen, see if you select a seat and then read the fare value.
So you need a loop. You can use something like this.
From you picture I can see that you only have 8 seats on there. But to make it quick lets just try and hit the the areas which also might have a seat and say that we are looking at 3x4 seats.
a = 0
b = 0
while a < 3
while b < 4
b += 1
end
a += 1
end
The outer loop will run 3 times, that is from front to back. The inner loop will run 4 times, that is seats left to right.
Now we need to make sure that we click on each position, so we add
performAction('click_on_screen',<x-value>, <y-value>)
And combined we have something like this.
Where you have x and y that are starting positions and should match the coordinates of the first seat.
Then at first run you just click at that location and do what ever you need to get the fare price.
After first click you increase the xOffset value by the distance between the two seats, and then you are ready to click on the second one. Please keep in mind, that I made this simpler so actually the second press will touch on the isle. But on the 3rd and the 4th you should again hit the seats.
And then you do that for the two next rows afterwards.
a = 0
b = 0
x = 100
y = 500
xOffset = x;
while a < 3
while b < 4
performAction('click_on_screen', xOffset, y)
b += 1
xOffset += 200
end
xOffset = x
y += 200
a += 1
end
Best regards
Lasse

How to store a gps coordinates in mysql, and then retrieve it without time lag?

I have completed a phonegap app which pools gps cordinate data every 10 sec to the server. now according to the calculations 8 hours of tracking it will store around 8*60*6=2880 records per user. my current requirement is limited to use of 20 user. (basically it tracks a users rout travelled)
There are two parts to the question:
what is the best way to store the data and retrieve it as fast as possible.
is it possible to display 2880 coordinates at a time on google maps API v3 ? if not, what is the best way to display the rout traveled?
I am having good results with 90 or so points, for one of my demos, but the enormous 2880 records per user per 8 hours is what worries me.
Thanks
EDIT 1
Although this is an old question , I recently worked on a project where I displayed about 10K points on the map, I hope my observations would help the future visitors:
The google maps as if now do not have a hard limit on the number of points you can display on the client side.
The number of points you can display on the client side is entirely dependent on the client side `Hardware` , bigger the number of points using a jpeg or gif marker , slower will be the renders , when moving around or zooming in and out
To have huge number of pointers on the map with a minimal performance hit, precomputing the number of points needed to be rendered before and after pan or zoom occurs will help a lot.
So here is a possible solution:
First of all, you need to find out how many points Google Maps API can handle and still show the line. I think this will just take some testing or researching. Anyways once you find your magical number of points to display to plot your path then take that number and multiply it by 2/3.
For instance if a good path needs have say 90 points then calculate 90*2/3
The reason for 2/3 is that the following loop will return a max number of points that is averagely equal to 3/2 times the variable we use so using. 60 would give us on average 90 plots. There is a case where the most returned plots would be (2 * (magical number of points)) - 1 for instance say we want on average of 90 points then we could in some rare cases have (2*(90*2/3))-1 = 119 points You will just have to do some testing after implementation to make sure that your magical number of points works good for maps with 2/3 of the magical number of points and 2 * magical number of points -1. I hope this isn't too confusing... I tried to explain as best I can.
The rest of this is going to be sudo code. You will have to adapt it for whatever language you connect to MySQL with:
//get the total number of rows returned
var total_rows = mysql->num_rows;
//calculate max to be 2/3 times your magic number for max plots, i.e. 90
var max_plots = 90*2/3;
//define empty plots array to fill with coordinates
var plots = array();
//check if total_rows is less than max_plots then:
if(total_rows > max_plots){
//find the quotient of the the divident total_rows and the divisor max_plots rounded down to the nearest whole int
var quotient = floor(total_rows/max_plots);
//define variable i to use in loop
var i = 1;
//loop through returned rows
while(row = mysql->fetch_row()){
//return only rows that are the first, last, or are dividable by the quotient evenly; Note: if your language supports it, use the Modulus operator like (i % quotient) == 0 for the last or statement.
if(i == 1 || 1 == total_rows || (i - (i * (floor(i/quotient)))) == 0){
//set plots to use on map
plots[] = array(
'lat' => row['lat'],
'lon' => row['lon'],
);
}
//increment counting variable
i++;
}
// else if total_rows less than or equal to max_plots retrieve all plots
} else {
while(row = mysql->fetch_row()){
plots[] = array(
'lat' => row['lat'],
'lon' => row['lon'],
);
}
}
This may not be the best way as it still requires to retrieve all of the rows from the database, but it does solve how to only print a selected maximum amount evenly spaced on the Google map.
Note: Be sure that your query orders the rows by an auto incrementing key or some other way so that the plots will be in order that they were entered into the database.
The most detailed maps would be a map with (2 * magic_plot_number) - 1 and your least details map would contain magic_plot_number or if lower, the number of total_plots. That being said an 8 hour tracking would plot a path with points every 7 minutes and 51 seconds totaling 61 points over 8 hours using the magic plot number of 90. The more plots the closer number of points will be to 2/3 * the magic plot number
I hope this helps you with this situation.

How to calculate moving average speed from GPS?

I'm developing an android application using GPS. I'd like to implement a feature that displays the users average speed over the 1/5/15 minute. Something like the CPU load on unix. I can calculate average easily by cumulating the distance traveled second by second and divide it by the elapsed time, but I can't think of a smart way of calculating the moving average.
Obviously I can get id done by putting the distance between the last and the current position in an array every second while deleting the oldest value.
I'm looking for a neat way of doing this.
Heres one way to go about it that is pretty straight forward:
If you are sampling position every second keep 901 samples in a queue, thats 15 mins worth (and 1 extra).
Position 0 is the most recent measurement, effectively your current position.
For an average speed over the last X minutes:
s = X * 60;
point1 = postion_queue[0]; // this is your current position
point2 = postion_queue[s]; // this is your position s seconds ago
d = distance_between_points(point1, point2);
speed = d / s;
speed is now distance units per second, convert to mph, or kph or whatever units you need. Different values of X can be used for any average between 1 and 15 minutes.
You will need to store all the values for the whole time span, as you already suggested. The reason is that you somehow need to "forget" the contributions of the old values to the moving average. You can't do that exactly if you don't know what these values where (i.e. if you do not store them).
In your case, 1 value each second for 15 minutes amounts to 15 * 60 = 900 data points, that should be OK.
Note that you do not need to perform a sum over the whole array each time you update: You can calculate the new moving average from the number of data points, the new value and the value you are "forgetting" at that moment:
new_average = (n * old_average - x_forget + x_new) / n
Here, n is the number of data points (900 in your case), x_forget is the value you are "forgetting" and x_new is the latest value. You then drop x_forget from the front of your array and store x_new at the end. Instead of an array you might want to use a queue implemented via a linked list.

Double # showing 0 on android

I'm embarrassed to ask this question, but after 45 minutes of not finding a solution I will resort to public humiliation.
I have a number that is being divided by another number and I'm storing that number in a double variable. The numbers are randomly generated, but debugging the app shows that both numbers are in fact being generated.
Lets just say the numbers are 476 & 733. I then take the numbers and divide them to get the percentage 476/733 = .64
I then print out the variable and it's always set to 0. I've tried using DecimalFormat and NumberFormat. No matter what I try though it always says the variable is 0. I know there is something simple that I'm missing, I just can't find it =/.
I imagine that you are trying to do something like this:
int x = 476;
int y = 733;
double result = x / y; // result == 0
The problem here is that you are performing integer division which gives the answer 0, and then afterwards converting the result to a double. You need to convert one or both of the numbers to floating point numbers before dividing. Here's one way to do that:
int x = 476;
int y = 733;
double result = ((double)x) / y;
I presume the 2 numbers that are being divided are "double" types?
Have you used debug mode to see the result of the division?

Categories

Resources