Mapping Pixels to Data - java

I've written some basic graphing software in Clojure/Java using drawLine() on the graphics context of a modified JPanel. The plotting itself is working nicely, but I've come to an impasse while trying to converting a clicked pixel to the nearest data point.
I have a simple bijection between the list of all pixels that mark end points of my lines and my actual raw data. What I need is a surjection from all the pixels (say, 1200x600 px2) of my graph window to the pixels in my pixel list, giving me a trivial mapping from that to my actual data points.
e.g.
<x,y>(px) ----> <~x,~y>(pixel points) ----> <x,y>(data)
This is the situation as I'm imagining it now:
A pixel is clicked in the main graph window, and the MouseListener catches that event and gives me the <x,y> coordinates of the action.
That information is passed to a function that returns a predicate which determines whether or not a value passed to it is "good enough", and filter though the list with that pred, and take the first value it okays.
Possibly, instead of a predicate, it returns a function which is passed the list of the pixel-points, and returns a list of tuples (x index) which indicate how good the point is with the magnitude of x, and where that point is with index. I'd do this with both the x points and the y points. I then filter though that and find the one with the max x, and take that one to be the point which is most likely to be the one the user meant.
Are these reasonable solutions to this problem? It seems that the solution which involves confidence ratings (distance from pix-pt, perhaps) may be too processor heavy, and a bit memory heavy if I'm holding all the points in memory again. The other solution, using just the predicate, doesn't seem like it'd always be accurate.
This is a solved problem, as other graphing libraries have shown, but it's hard to find information about it other than in the source of some of these programs, and there's got to be a better way then to dig through the thousands of lines of Java to find this out.
I'm looking for better solutions, or just general pointers and advice on the ones I've offered, if possible.

So I'm guessing something like JFreeChart just wasn't cutting it for your app? If you haven't gone down that road yet, I'd suggest checking it out before attempting to roll your own.
Anyway, if you're looking for the nearest point to a mouse event, getting the point with the minimum Euclidean distance (if it's below some threshold) and presenting that will give the most predictable behavior for the user. The downside is that Euclidean distance is relatively slow for large data sets. You can use tricks like ignoring the square root or BSP trees to speed it up a bit. But if those optimizations are even necessary really depends on how many data points you're working with. Profile a somewhat naive solution in a typical case before going into optimization mode.

I think your approach is decent. This basically only requires one iteration through your data array, a little simple maths and no allocations at each step so should be very fast.
It's probably as good as you are going to get unless you start using some form of spatial partitioning scheme like a quadtree, which would only really make sense if your data array is very large.
Some Clojure code which may help:
(defn squared-distance [x y point]
(let [dx (- x (.x point))
dy (- y (.y point))]
(+ (* dx dx) (* dy dy))))
(defn closest
([x y points]
(let [v (first points)]
(closest x y (rest points) (squared-distance x y v) v)))
([x y points bestdist best]
(if (empty? points)
best
(let [v (first points)
dist (squared-distance x y v)]
(if (< dist bestdist)
(recur x y (rest points) dist v)
(recur x y (rest points) bestdist best))))))

Related

Easy point-in-polygon-test with consistant behaviour for edges

While searching for point-in-polygon tests I've found the one described by Dean Povey here. I like the approach as it can be easily understood (raycast along the x-axis) but I've come across a small inconsistency with that method. While writing Unit-Tests for my implementation I noticed that when taking a square as a "Test-Polygon" points on the left and bottom edge of the square are recognized as part of the polygon while points on the right and top side of the polygon are recognized as outside the polygon. Here's a small drawing showing what I mean (+ are not recognized as inside, doubled lines and the x are):
+--------+
‖ |
‖ |
x========+
Does anyone know how I can change the algorithm to show consistent behaviour for points on the edge? It doesn't matter if the edges are considered as inside or not, just that the behaviour is consistant.
To test if a point P lies on an edge QR, consider the transformation that maps Q to the origin and R to the point (0, 1).
Using complex numbers, write this transformation as Z = (z - Q) / (R - Q) and transform P with (P - Q) / (R - Q). This number must be pure real and its real part be in [0, 1].
You can use this test to detect points on the outline. It is also possible to allow a tolerance, by allowing the imaginary part to be a small number. In this case, it is advisable to normalize the denominator R - Q, so that the imaginary part becomes the Euclidean distance to the segment.

How to convert an angle to a vector

I'm making a simple 2d Java game similar to goemetry wars. I'm currently programming the player's shooting.
I have a target point specified by the mouse location. Now I want to add a bit of randomization, so that the shooting angle has a random offset. I am currently converting the point to a vector directly. My idea was to convert the vector to an angle, apply the randomization to that angle, and then, convert the angle back to a vector (given the length of the vector).
I can't figure out how to convert the angle back to a vector. I don't need code, it's basically just a question about the maths.
If there's a better way to randomize the shooting, I would love to hear that too! I can!t apply the randomization to the point because there are other things then the mouse that can set it.
Polar coordinate system
As everybody seems to have just answered in the comments, here goes the answer to your question as it is formulated : you need to use the polar coordinate system.
Let's call your angle a, the angle you want to add to it b, so the modified angle is a+b.
In the polar coordinate system, your point is represented by an angle a = Math.atan2(y, x) and a radius r = sqrt(x*x + y*y). If you just use the angle, you loose some information, which is at which distance the mouse is from your (0,0) point.
Converting back from your polar representation (after the angle has been modified) is now possible : x = r * Math.cos(a+b), y = r * Math.sin(a+b)
Without computing the angle
By using some cool trigonometry formulas, we can do better. We don't need to go to an angle and come back to a vector, we can modify the x and y values of the vector directly, still changing the angle like you want.
Remember that we want to find x'=r cos(a+b) and y'=r sin(a+b). We will obviously the following formulas :
Now let us multiply by r on both sides to get what whe want.
We now recognize x=r cos(a) and y=r sin(a), so we have the final expression :
If you come to think of it, for small values of b (which is what you want), sin(b) is close to 0, and cos(b) is close to 1, so the perturbation is small.
Not only do you reduce the number of trigonometry operations from 3 to 2, but you also have a cos and a sin of small values, which is nice if they are computed from Taylor series, makes convergence very fast. But that's implementation dependent.
NB: An alternative (and more elegant?) way to find the same result (and exact same formulas) is to use a rotation matrix.
I can haz cod
Whoopsie, you said you didn't want code. Well let's do it like this : I don't post it here, but if you want to compare with how I'd do it once you're done coding your implementation, you can see mine in action here : http://ideone.com/zRV4lL

Java - Detect Straight Lines with given Coordinates

ADDED INFO:
I'm using the inside of a square as an arena. On start up, the square spawns in a random position, and rotation, and I can't access any of the squares attributes.
I then have a moving object inside the square, that I'm building AI for, and I want the object to 'learn' where the arena walls are. Every time the object bumps into a wall, I get a touch return, so I know if its hit or not. I'm using this to map the global position of where the object hit the wall and save it ... After 3 hits on the same wall, I want to mathematically 'draw a straight line' down those dots which will represent the arena walls - with this, I can tell my object not to go near these coordinates.
The reason for 3 dots? Well, if the object hit one side of a wall, then was to hit another side of a wall, I will have a line drawn from one side to another, giving false data about where the wall is.
If Java sees three (or more) dots inline, it knows that the object has hit the same wall (either being further up or so).
CONTINUED:
I'm trying to map out lines with given coordinate data. Basically I have an array that holds X and Y coordinates, and I want to be able to mathematically detect if it's they make up a straight line (give or take a few pixels). (The coordinate are a boarder of a square)
For example, the array might be like this:
[x0][y0] - 1,1
[x1][y1] - 2,2
[x2][y2] - 5,5
Which will present a diagonal line of on side of the square, like so:
But sometimes I might get one coordinate of one side of the square, and then another side, all mixed up (and not necessarily on a 90 degree angle either!). So I want to be able to run through the array, and detect what coordinates make a line (or the boarder side of the square), like so:
So right now, I have a 2D array:
private double wallLocations[][] = new double[10][10];
and a while loop that doesn't do the job. I don't really know where to even start with this one:
for(int r = 0; r < wallIndex; r++){
for(int c = 0; c < wallIndex; c++){
int index = 0;
if(wallLocations[r][index] == wallLocations[r][c] && wallLocations[r][index + 1] == wallLocations[r][c] &&
wallLocations[r][index + 2] == wallLocations[r][c]){
System.out.println("***** Wall Here! *****");
index++;
}
}
}
---- UPDATE ----
Heres a better example in what I'm looking for. The red dots represent the coordinates coming in, a line is detected when 3 or more dots line up (if it was 2 dots, then it would detect any and ever dot) ... You notice that this is starting to look like the boarder of a square?
This seems to essentially be a clustering problem, and those can be generally pretty hard. Part of a reason clustering is hard is that there may be more than one applicable mapping.
For instance (please forgive my bad ascii art):
X X X
X X X
X X X X
could be mapped
X---X---X X X X
\ / \ / \
X---X---X or X X X
/ \ / \ \
X---X---X---X X X X X
I've seen uses of the Expectation Maximization algorithm using mixed Gaussian models used for this kind of thing (when there were a lot of points but only a few expected lines) but you generally do have to give that algorithm a definite number of clusters, and while its results are good, it's a pretty slow algorithm requiring possibly many iterations. I'm kinda thinking I've seen something generally faster that's some sort of image processing algorithm but I'd have to do some research.
I'm kinda wondering about something where you find y=mx+b for every pair of points and them sort them over m and b. It might be advantageous to find the angle θ in [0,pi) for each pair instead and sort over the angles instead of m, or maybe beter cluster by cos(2θ)-- the point of that being that the group of lines {y= -0.0001x + 1, y =1, and y=0.0001x + 1} are very similar, the group of lines {y= -10000x + 10, x = 0, and y=10000x - 10} are also very similar, but cos(2θ) should put them as far apart as possible, as any two pairs between each group should be nearly perpendicular.
Also note, in my example, b doesn't matter much for the lines nearly perpendicular to the x axis, so "b" might not be so useful for direct clustering.
I guess, perhaps, there may be some utilizable measure of "distance" between two lines, I'm just not sure what it would be. Two lines that are nearly parallel that converge "on screen" (where the points generally are) might ought to be considered "closer" than if they converge a trillion units a way from the screen--or should they? Purely speaking, three lines can never pairwise be considered closer to one another if none of them are parallel (If they're on a plane, they'll all meet somewhere), but intuitively, if we have two lines that are generally one inch apart in the area we're concerned with, we'd pick that pair as closer over two identically pointed lines that are a mile apart in the area of concern. That makes me think maybe the area between the lines,as bound by our area* ought to be used as a metric.
Sorry, I'm not sure how useful all that brainstorming might be, but it might put a different light on things.
Edit: You know what, a better answer might possibly be found by researching this:
http://en.wikipedia.org/wiki/Hough_transform
Edit II & III:
Ok,... the situation you've just described is a lot simpler and less generic (although, to be honest, I think I misread your initial query to be more generic than it really was).
You've got 4 candidate walls. Let your AI bounce around until it finds three co-linear points. That should be a simple test of combinations. Assign those three points a wall. Depending upon what other points you have, you actually might be able to determine or at least estimate the other three walls (assuming it is a square). If you have 5 points with 3 on separate walls, you should be able to calculate the distance between walls, and therefore the likely position of the 4th wall. To test if the other two points are on separate walls, make sure they're pair-wise not co-linear with a line perpendicular or parallel to the line defined by your wall, or if they are on a line parallel, test to see if the distance between them is less than the distance between the wall and them (if that's the case, they're on the wall opposite of the first candidate wall). Given that they are on separate walls, either one is facing the first found wall, or they're on walls perpendicular to that wall. Either way you can find the lines defining the walls with a little tricky geometry.
(and actually, to determine the dimensions, I don't think you need to even test to see that you have 3 co-linear points... I think you just need to test to see that you've made two turns... which takes 4 points minimum but likely more if you're unlucky. two of the points would have to be determinable to be on a different wall from the other two, which means really big bounces!)
There's a bit of math involved, and I'm a bit too tired to explain further tonight, and I don't know how much of the geometry of points around a square you want to take advantage of, because you wouldn't be able to use those properties in a more general case, so I'll leave it at that, and maybe also remove some of my other previous brainstorm cruft later.
If you have two points you can calculate the slope of the connecting line with Math.atan2.

scaling operations on a 2D graph, size of output sequence must not be the same as input

I am looking for an open source package (preferably Java but R or other languages would be ok too) that provides these 2 functions
1) points output_seq[] SCALE(points input_seq[], double factor)
In other words a sequence of doubles (x1,y1), (x2,y2)... is given as input that represents a graph (each point is connected to the next by a straight line) and a scaling factor is given. Then it returns a similar sequence as output. The catch is that the output sequence may have fewer or more elements than the input. For example, if I request magnification by a factor of 2.012 then the output sequence may have twice as many elements as the input. The scaling factor should be a double, not an integer.
Lastly, it's important to return the output sequence as points (doubles), I have very little interest in the actual drawing on a screen beyond proving that it does the right thing.
2) points output_seq[] ROTATE(points input_seq[], double angle)
same as above, except there is no scaling but just rotation, the angle is from 0 to 359.9999 and is given in radians.
The size of the output is always the same as the size of the input.
Again the emphasis is on getting the output sequence as doubles, not so much on the actual drawing on a screen.
If you know the right terminology I should have used then let me know.
Thank you so much.
In Java, Path2D is suitable for 2D floating point coordinates. The lineTo() method will add straight lines to the path. Because Path2D implements the Shape interface, rotate and scale are possible via createTransformedShape(). One approach to interpolation, using PathIterator, is shown here.

Get from java hashmap based on 2d distance

I am making a strategy game in android with lots of units and I have come to a point where I need to check the position of every single object against every other one to see if the two are close enough together that they should start fighting. Right now the only way I can determine if two units are close enough is in this method:
public boolean inProximity(float x2, float y2) {
return Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)) <= proximityRadius;
}
I don't want to be iterating through all the units an n-squared amount of times. I was looking at a TreeMap to store the positions, but then how would I (if it's even possible) get the keys based of distance from a unit?
You might want to reconsider the data structure here and take a look at quadtrees. They essentially allow you to partition 2D space and do collision detections which seems to be your use case.
http://en.wikipedia.org/wiki/Quadtree
Just doing a google on java quadtree produces some hits on implementations. I haven't used any of them so I can't really vouch for them, but that should give you something to go on.
1) As a first thing to think about, you don't need to take the square root. The square and the square root both increase as the numbers increase, so that would be one optimization.
2) This is known as the 'Closest Pair' problem, and there are divide-and-conquer based algorithms to solve it.
Take a look at: http://en.wikipedia.org/wiki/Closest_pair_of_points_problem

Categories

Resources