Filling in the Area between of two lines which intersect? - java

Is it possible to fill in the area between a Dataset plotting a XY line and a ValueMarker ?
See picture for the general idea(Warning: My MS Paint skills are lacking).

As lschin, XYDifferenceRenderer is the best way to do this. In order to have this work you need to create two separate multidimensional double arrays to store to X and Y coordinates. The first array is set to store your a XY line's x and y coor's. The second array is a constant XY line. To set this line up you X values are the same. If your original line is above your constant line, the Y value is the coordinate you choose of position of the constant line. If the original is below the constant then the Y value of the constant is that of your original line. I hope that makes sense and is helpful to anyone, ive attached code below for better understanding.
setConstant = position of your constant line.
The code below is placed in a loop:
indLine[0][i]= XYIndLine.getXValue(1, i);
indLine[1][i] = XYIndLine.getYValue(1, i);
constant[0][i] = XYIndLine.getXValue(1, i);
constant[1][i] = Math.min(setConstant, XYIndLine.getYValue);
once this is done then use addSeries to add the two arrays to a DefaultXYDataset

Related

Fastest way to check which rectangle is clicked in a list of rectangles

I have a rectangle Object with x, y, width and height. I have a list of these rectangles which are displayed on a screen. It is guaranteed that none of them overlap. Given a user's click position (x and y coordinates), I want to see which of these rectangles were clicked (since they do not overlap, there is a maximum of one rect that can be clicked).
I can obviously look through all of them and check for each one if the user clicked it but this is very slow because there are many on the screen. I can use some kind of comparison to keep the rectangles sorted when I insert a new one into the list. Is there some way to use something similar to binary search in order to decrease the time it takes to find which rect was clicked?
Note: the rectangles can be any size.
Thanks:)
Edit: To get an idea of what I am making visit koalastothemax.com
It highly depends upon your application and details we're not quite aware of yet for what the best solution would be. BUT, with as little as I know, I'd say you can make a 2D array that points to your rectangles. That 2D array would map directly to the pixels on the screen. So if you make the array 10x20, then the coordinate x divided by screen width times 10 (casted to int) will be the first index and y divided screen height times 20 would be your y index. With your x and y index, you can map directly to the rectangle that it points to. Some indexes might be empty and some might point to more than one rectangle if they're not perfectly laid out, but that seems the easiest way to me without knowing much about the application.
I have tackled a very similar problem in the past when developing a simulation. In my case the coordinates were doubles (so no integer indexing was possible) and there could be hundreds of millions of them that needed to be searched.
My solution was to create an Axis class to represent each axis as a sequence of ranges. The ranges were guaranteed to go from a minimum to a maximum and the class was smart enough to split itself into pieces when new ranges were added. Each range has a single generic object stored. The class used a binary search to find a range quickly.
So roughly the class looks like:
class Axis<T> {
public Axis(double min, double max, Supplier<T> creator);
public Stream<T> add(double from, double to);
public T get(double coord);
}
The add method needs to return a stream because the added range may cover several ranges.
To store rectanges:
Axis<Axis<Rectangle>> rectanges = new Axis<>(0.0, 100.0,
() -> new Axis<>(0.0, 100.0, Rectangle::new));
rectangles.add(x, x + w).forEach(r -> r.add(y, y + h).forEach(Rectangle::setPresent));
And to find a rectangle:
rectangles.get(x).get(y);
Note that there's always an object stored so you need a representation such as Rectangle.NULL for 'not present'. Or you could make it Optional<Rectangle> (though that indirection eats a lot of memory and processing for large numbers of rectangles).
I've just given the high level design here rather than any implementation details so let me know if you want more info on how to make it work. Getting the logic right on the range splits is not trivial. But I can guarantee that it's very fast even with very large numbers of rectangles.
The fastest way I can come up with is definitely not the most memory efficient. This works by exploiting the fact that an amortized hash table has constant lookup time. It will map every point that a rectangle has to that rectangle. This is only really effective if your are using integers. You might be able to get it to work with floats if you use a bit of rounding.
Make sure that the Point class has a hash code and equals function.
public class PointCheck
{
public Map<Point, Rect> pointMap;
public PointCheck()
{
pointMap = new HashMap<>();
}
/**
* Map all points that contain the rectangle
* to the rectangle.
*/
public void addRect(Rect rect)
{
for(int i = rect.x; i < rect.x + rect.width; ++i)
{
for(int j = rect.y; j < rect.y + rect.height; ++i)
{
pointMap.put(new Point(i, j), rect);
}
}
}
/**
* Returns the rectangle clicked, null
* if there is no rectangle.
*/
public Rect checkClick(Point click)
{
return pointMap.get(click);
}
}
Edit:
Just thought I should mention this: All of the rectangles held in the value of the hash map are references to the original rectangle, they are not clones.

Optimally searching for 2D points in the given area (webservice)

I've got a kind of algorithmic & performance problem to solve with Java. I've got a large collection of 2D points (let's say there are about 100 000 of them). I want to get a set of them that are in the given area around the search point SP(X_sp, Y_sp), so that I'd like to get the points P(x y) that meets the criteria:
x is between X_sp - constValue and X_sp + constValue AND y is between Y_sp - constValue and Y_sp + constValue
To give you an idea of the number relations, constValue will be like 2, 5 or 10, and x, y will range between 0 and 1000. It's meant to be a webservice, so a possibility of searching around many different points at the same time must be taken into account.
As these are fixed points (not to change due to calculations or something), I thought that it would be optimal to provide one list of objects sorted by X and another one, but sorted by Y. Then, I'll first get the points within the X range, and, using references, get the set of this points from another list (sorted by Y). Then I'll narrow this selection by Y and in result get the points in the given area.
I don't know Java inside-out, so I'd like to consult with you the most optimized approach. Which objects should I use to store sorted points, which allow for fast search of objects within range? Or maybe I have to implement my custom algorithm for this task? Also, when it comes to storing the points in the database, are SQL queries sufficiently fast to deliver the results? Or maybe NoSQL dbs are better for this?
I'm going to perform my own tests, but I'm looking for a starting candidates.
I'd probably use a TreeMap<Integer, TreeSet<Integer>>, where the key to the map is the x coordinate and for each x coordinate, you have a list of y coordinates. You can then use floorEntry and ceilingEntry to find the x coordinates that fall within your range. Then for each TreeSet<Integer> set that you get, you can use ceiling and floor to get the appropriate entries.
Of course, this only gives you the coordinates of the bounds of your box (the four corners). But TreeSet also has a subset that will give you a range of values. You will have to use this twice; once for the list of x coordinates (you can get the key set using the keySet method of the map) that are within your bounds, then for each x coordinate, the y coordinates that are within the bounds. So the pseudocode would be sort of like this:
List<Point> result = new ArrayList<>();
int lowerX = points.ceilingKey(x - c);
int upperX = points.floorKey(x + c);
for each x coordinate in points.entrySet().subset(lowerX, upperX)
TreeSet<Integer> yCoordinates = points.get(x);
lowerY = yCoordinates.ceiling(y - c);
upperY = yCoordinates.ceiling(y + c);
for each y coordinate in yCoordinates.subset(lowerY, upperY)
result.add(new Point(x, y))
I haven't tested this out, so there are probably some bugs or something I've missed. Let me know and I'll correct the answer.
The floor and ceiling calls are log(n) I believe -- this is where you get the performance benefit because if you use a list, it would be O(n) to look that up.
Note: I don't know if this is the most performant. SO is typically not the place for such an open-ended question so you might have more luck elsewhere.

good way to seperate List<Integer> into 5 lists of chunks around the 5 minimums

Ok guys, time to get creative.
I have a list of integers, and want to preserve the integers in the 5 green boxes below.
I thought about finding the 5 minimums, and then going left and right from each one until the next integer is a certain distance too far. However this may be difficult to do as the last to boxes have some scattered values that I would like to maintain.
So cliff notes,
have list of integers that i want to make 5 lists of integers from, each one of the 5 lists holding the values of one of the green boxes.
I am sorry if this question seems dumb, I was just wanting to see if other people had better ways of going about this then the one I mentioned above.
Edit:
Perhaps a Levenberg-Marquardt algorithm would help? If only I could understand math books xD. I swear math explanations are never written in English, but if someone just shows me the use, and how to, I get it and understand it. Then I can go read it out of a book again and just be confused all over again!
That could be a possible solution:
Let call your list of integer P[n].
define a new list of point, we call it MAX[n], calculated this way:
if ((MAX[n] < P[n]) || (n == 0))
MAX[n] = P[n];
else
MAX[n] = MAX[n-1];
in this way, MAX[n] list will be the green line above your graph:
FIRST SOLUTION:
to identify the points inside the green boxes, you just have to calculate the incremental ratio of your P list, and check when its absolute value is smaller than a threshold:
I = [P[n+1] - P[n]] / [T[n+1] - T[n]]
so a point is into the green box if I is below a threshold and P is below MAX:
if ((P[n] < MAX[n]) && (ABS(I) < DER_THRESHOLD))
// your point is inside the green box
from your graph, roughtly, you could put DER_THRESHOLD = 5.
SECOND SOLUTION:
calculate a new list of integers, called this time AVG[n] like that:
AVG[n] = (MAX[n] + P[n]) / 2
this will end in the red line (sorry for the ugly graph, did it by hand):
and now you can identify green boxes just checking if your P[n] is below AVG[n].
This solution could be even better using some kind of low filtering in AVG calculation.
Try finding the least squares fit line through the points, and then look at whether the points are above or below the line. That will split your points into the five green boxes below the line, and the six infrared boxes above the line. It will also include the points inbetween the boxes, but those will be easy to exclude because of the big jump before or after the point that should be excluded. But it's also looking like you may have trouble at the top right of this data set.

How to get Point values from ArrayList

I have a small problem that I hope is easy to solve. In the code below on the second row I have path1.moveTo... but instead of using the touchDownX1 and touchDownY1 coordinates, I thought it would be better to use the first values of X and Y from the touchPoints[0], but I don't know how?
// Path 1
path1.moveTo(touchDownX1, touchDownY1);
for(Point point: touchPoints[0]) {
path1.lineTo(point.x, point.y);
canvas.drawPath(path1, paint1);
}
You have to write touchPoints.get(0) because the [index] notation only works for arrays, not ArrayLists.
Edit:
The rest of the code should work. The way you access x and y is perfectly fine, assuming that the first element touchPoints is a list of points. If the first element of touchPoints is a single point, do not use a loop, just do touchPoints.get(0).x and the same for y.
Edit:
The moveTo method should only be called for the beginning of a contour/shape to set its starting point. There is no reason to call it more than that for a single contour.

Join two lines in one line (in Java)

I have an array of Lines and I am using it to draw vectors in my map.
I want to replace two superposed Lines (or have short distance between them) with one Line. Can you give an algorithm to do that ?
Here is a picture that helps you to understand this problem:
The Input Lines :
After executing the algorithm, I would like to to get the output represented in the following picture:
PS: A Line is an ArrayList of points.
Merge any pair of vertices that are within some fixed distance of each other (set their position to be equal).
Find the nearest point on each line to each vertex. If it's close enough, then split the line on that point, and merge the points.
Remove duplicate lines that have the exact same start and end points.
For example, if you have a line defined by points A and B, and another line with point C (diagram on left above). The point D can be found using a shortest distance from point to line function. If D is too far away from C then ignore it, otherwise split the line AB into two lines AD and DB, and move all points in position C to position D, to get the diagram on the right.
This question is similar to the question "Do two ranges intersect, and if not then what is the distance between them?" The answer depends slightly on whether you already know which range is smallest already, and whether the points in the ranges are ordered correctly (that is, whether the lines have the same direction).
So a preliminary algo approach will be like this :
if (a.start < b.start) {
first = a;
second = b;
} else {
first = b;
second = a;
}
Let us find the distance now :
distance = max(0, second.start - first.end);
Now you have must have a range of values for shortest distance , depending on which you are going to super impose the lines into 1 . Lets say you have kept them in an array called :
arrayRange[];
Now if ,
for(int 1=0;i<arrayRange.length;i++)
{
if(distance is one of the elements of the arrayRange)
then,
callFunctionSuperImposeLines(distance,a,intersectionPoint,a.end,b,b.end);
}

Categories

Resources