I have 2 sections, each section contains of 2 Points and each point has X and Y.
What is the best way to find the overlap between these 2 sections? (only on the X relevant here)
public class section
{
double leftPoint;
double rightPoint;
}
Doesn't the rectangle class has methods for this?
If you create two rectangle's (sized and positioned just like those "sections") you can compare them using intersection() what will return an Rectangle of the overlapping area.
Here is example code to show you how to do it. I assume the two sections are (a_from, a_to) and (b_from, b_to) and set the resulting section to be (res_from, res_to). Also I only intersect the intervals on the x-axis as this seems to be what you want. The idea is that the results starts from the later of the two beginnings and ends at the earlier of the two ends.
Point a_from, a_to;
Point b_from, b_to;
Point res_from = new Point();
Point res_to = new Point();
res_from.SetX(Math.max(a_from.getX(), b_from.getX()));
res_to.SetX(Math.min(a_to.getX(), b_to.getX()));
Note that if res_to.x < res_from.x There is no intersection at all.
Also here I assume a_from.x <= a_to.x and b_from.x <= b_to.x which may not always be true. If it is not you have to calculate res_from.x as Math.max(Math.min(a_from.getX(), a_to.getX()), Math.min(b_from.getX(), b_to.getX()))
Related
I want to do some geometric calculations in Java and found that Spatial4j should suit my needs.
I want to be able to compute stuff like whether two polygons overlap or what their bounding box is.
My thinking is that I need to create a polygon from a series of points.
To that end I have tested with this code:
Point point1 = shapeFactory.pointXY(0, 0);
Point point2 = shapeFactory.pointXY(5, 1);
Point point3 = shapeFactory.pointXY(3, 3);
Point point4 = shapeFactory.pointXY(0, 1);
List<Point> points = new ArrayList<>();
points.addAll(Arrays.asList(point1, point2, point3, point4));
So, I have my points now. How do I go about making a polygon (or for that matter any shape) from these points ?
I would think that shapeFactory.polygon() would create me a polygon but that throws me an UnsupportedOperationException. Any help ?
Alright, it seems that Spatial4j does not connect the points, so it is not a filled shape. Instead I relied on the Spatial4j implementation of JTS and that did the trick. (Spatial4j's polygon is not implemented).
JtsSpatialContextFactory jtsSpatialContextFactory = new JtsSpatialContextFactory();
JtsSpatialContext jtsSpatialContext = jtsSpatialContextFactory.newSpatialContext();
JtsShapeFactory jtsShapeFactory = jtsSpatialContext.getShapeFactory();
ShapeFactory.PolygonBuilder polygonBuilder = jtsShapeFactory.polygon();
// note due to it being a builder one needs to chain the points.
Shape shape1 = polygonBuilder.pointXY(4, 0).pointXY(3, 3).pointXY(1, 4).pointXY(0, 0).pointXY(4, 0).build();
Now doing for example shape.getArea() returns the surface area.
One can also create a Geometry from a Shape by doing jtsShapeFactory.getGeometryFrom(shape), which then returns a Geometry.
Note: Watch out with doing polygonBuilder.pointXY() even after calling build(). It will still append these points to whatever was chained to the builder before the build.
I have a rectangle array holding multiple objects, moving back and forth on X axis.
Iterator<Rectangle> iter = array.iterator();
while ( iter.hasNext() ) {
Rectangle obj = iter.next();
array.get(i).x += speed * Gdx.graphics.getDeltaTime() ;
if (obj.x + obj.width > 800 || obj.x < 0) {
speed = -speed;
}
}
When the speed gets bigger, you'll start noticing the first object in the array overlapping with the other objects and pushing them apart. How to fix that?
Basically each object has
Rectangle obj = new Rectangle();
obj.x = xpos;
obj.y = ypos;
obj.width = width;
obj.height = height;
xpos += width + 4;
And has a texture, image, a sqaure, a rectange, a triangle... And each object is generated at an X position xpos different than the other. All they do is keep moving on the X axis, from x=0 till 800 and back.
What happens is that when the first object gets to 0, it tries to increase its speed again and overlapping with other objects, and then time after time, all objects keep overlapping and get further apart from each other. I want the distance between the objects to stay constant at any speed.
From what you've commented, the questions appears to be "How can I make all these blocks move together, bouncing from one edge to another". The issue being that you're getting bouncing, but they stop acting as a group.
Firstly, if you want to treat them as a group - the simplest way is to consider them as one large bounding box containing lots of smaller (inconsequential) objects. Moving that as a single object from side to side will give you the behaviour you need.
That aside, the direct answer to your question is "you're changing the direction mid-way through iteration". So in any single tick, some objects have moved left and some have moved right - meaning they stop acting as a group.
How you organise it is up to you, but this is the basic idea you need:
// assume "speedForThisFrame" is a float defined outside this function
float speedForNextFrame = speedForThisFrame
// iterate through however you want
Iterator<Rectangle> iter = array.iterator();
while ( iter.hasNext() ) {
Rectangle obj = iter.next();
obj.x += speedForThisFrame * Gdx.graphics.getDeltaTime() ;
// if it's moved out of bounds, we will change direction NEXT fame
if (obj.x + obj.width > 800 || obj.x < 0) {
speedForNextFrame = -speedForThisFrame;
}
}
// now that all movement has finished, we update the speed
speedForThisFrame = speedForNextFrame
The key thing is everything must move by the same amount, in the same direction, every frame. Changing the speed mid-update will cause them to act independently.
Note, you will still have issues when your group is larger than the bounds - or when they go over the bounds in one frame and don't fully get back the next frame. These are separate issues though and can be asked in a separate question.
I think your problem is that, caused by variations in Gdx.graphics.getDeltaTime(), the rectangles exceed your 0/800 borders by different distances.
An example:
First step:
Rect #1 x=790
Rect #2 x=780
Speed=100, DeltaTime=0.11 => DeltaX=11
After this step, Rect#1 would be at 801, Rect#2 at 791, their distance is 10.
Next step:
DeltaTime=0.12 => DeltaX=12
After this step, Rect#1 is at 789, Rect#2 at 803, their distance is 14.
Your rectangles vary their distance because they travel different distances. A possible solution would be to really bounce at the borders. So you should not only invert the speed but also take the distance a rectangle exceeded the border and let it travel this distance in the opposite direction:
So Rect#1 at 790, moving 11 pixels rightwards, should not be at 801 in the end of the step but at 799 (moving 10 pixels to the right and one to the left).
I am trying to set a location of geometric figure that appears in JFrame window. For example if it's a rectangle so i need to move it's left upper point 10 pixels right, and left lower point 10 pixels down.
I was trying to do like this but it didn't work:
public void relocate(ArrayList<MyShape> newShape){
int x1, x2, y1 , y2;
for(int i = 0; i < newShape.size(); i++){
x1 = (int)newShape.get(i).p1.getX();
y1 = (int)newShape.get(i).p1.getY();
x2 = (int)newShape.get(i).p2.getX();
y2 = (int)newShape.get(i).p2.getY();
newShape.get(i).setLocation(x1 + 10, y1);
newShape.get(i).setP1(newShape.get(i).getP1());
newShape.get(i).setLocation(x2, y2 + 10);
newShape.get(i).setP2(newShape.get(i).getP2());
if(newShape.get(i).getCol() != null){
newShape.get(i).setCol(Color.BLUE);
}
}
repaint();
}
Your code should work - in a sense that it changes the location of the objects on the screen. So, what's going on here? What's wrong with your solution?
I can give you a few hints though:
You can check if any other part of the code is messing with the location setting. It's possible that they override your settings.
Maybe this code runs outside of the AWT Thread. You can check it with SwingUtilities.isEventDispatchThread().
You can reuse the Point-s in Swing. Points are mutable object. This leads to not so clean code, but performance is important in this case:
MyShape shape = newShape.get(i);
Point p = shape.getP1();
p.setLocation(p.x, p.y + 10);
Maybe a revalidate() call can help too:
public void relocate(ArrayList<MyShape> newShape) {
// some code changing locations
revalidate(); // this is it
repatint();
}
The following analysis is based on assumptions about how MyShape works since you've declined to provide those details when asked for them.
Look at your algorithm. For each shape:
1) You're capturing the original values of P1 and P2. So far so good.
2) You're calling the shape's setLocation() method with an adjusted value for P1. Now, what does setLocation() do? Understanding that is part of why you were asked about the MyShape class, and saying it's a superclass for all shapes doesn't help.
3) You tell the shape to set its P1 to whatever value you get by querying its P1. If the getters and setters do anything reasonable, this won't do anything.
4) You then call setLocation() again, this time with an adjusted value for P2. Again, what does this do? It probably undoes whatever you accomplished in step 2.
5) You tell the shape to set its P2 to whatever value you get by querying its P2. Again, this probably doesn't do anything.
What you want to do, I assume, is set P1 based on the adjusted values you calculated in step 2; and set P2 based on the adjusted values in step 4. But that's not what your code says unless secLocation, getP1, and getP2 are all doing very ununtuitive things.
Not sure what MyShape does, but it seems that newShape.get(i).setP1 just overrides newShape.get(i).setLocation right before it. Try adjusting your code like this:
//Change this
newShape.get(i).setLocation(x1 + 10, y1);
newShape.get(i).setP1(newShape.get(i).getP1());
newShape.get(i).setLocation(x2, y2 + 10);
newShape.get(i).setP2(newShape.get(i).getP2());
//To this
newShape.get(i).getP1().setLocation(x1 + 10, y1);
newShape.get(i).getP2().setLocation(x2, y2 + 10);
I hope this helps.
Got this BOID application going in Processing with some steering algorithms.
The boids are stored
in two separate ArrayLists for each colour.
The red boid (predator) has a
pursue function:
class Creature {
int prey = 1;
PVector pursue(ArrayList boids) {
PVector steer = new PVector();
if (prey < boids.size()) {
Creature boid = (Creature) boids.get(prey);
steer = PVector.sub(boid.location, location);
steer.mult(maxpursue);
}
return steer;
}
This function gets the red boids to stand on top of the targeted white boid.
The problem is getting this white boid to disappear when all the red boids are on top of it. (Like shown in the image above)
I can add a new boid or predator with the following, but i cannot remove?:
void mousePressed() {
if (mouseButton == LEFT){
Creature predator = new Creature(mouseX, mouseY, 2);
planet.boids.add(predator);
} else if (mouseButton == RIGHT) {
Creature boid = new Creature(mouseX, mouseY, 1);
planet.boids.add(boid);
planet.boids.remove(boid); // This line does not work?
}
}
The code you posted doesn't make a ton of sense. You want to remove an existing Boid, so why on earth are you creating a new one and then immediately removing it?
You haven't posted an MCVE, so I can only answer in a general sense, but here's what you need to do:
Step 1: Refactor your code so that it makes more sense. Comment every single line if you have to, just to be sure you know exactly what the code is doing. But you shouldn't be doing things like adding a new Boid and then removing it in the very next line. Break your problem down into smaller steps, and make sure each step works perfectly by itself before trying to mix it with other funtionality.
Step 2: Create a function that takes a single white Boid and the List of red Boids, and returns true if that white Boid should be removed. Test this function by itself using hard-coded values in a standalone example sketch.
Step 3: Iterate over your white Boids and call the function you created in step 2 for each one. If the function returns true, then remove that white Boid. You might want to use an Iterator for this step.
If you get stuck on one of those steps, then post an MCVE along with a specific question, and we'll go from there. It's hard to answer general "how do I do this" type questions, but it's much easier to answer specific "I tried X, expected Y, but got Z instead" type questions- especially if we have an MCVE we can actually run on our own machines instead of some disconnected snippets.
I am using the following code to find a point of coordinates exists in the code or not:
mMap.setOnMapClickListener(new OnMapClickListener()
{
public void onMapClick(LatLng point)
{
boolean checkPoly = true;
Point2D[] points = new Point2D[ myPoints.size()];
for ( int i = 0; i < myPoints.size(); i ++)
{
LatLng pt = myPoints.get(i);
points[i] = new Point2D(pt.latitude, pt.longitude);
}
Polygon2D polygon2d = new SimplePolygon2D(points);
double a = point.latitude;
double b = point.longitude;
Point2D myPt = new Point2D(a,b);
checkPoly = polygon2d.contains(myPt);
Log.i("CHECK", String.valueOf(checkPoly));
if (checkPoly)
{
setMarker(point);
}
else
Toast.makeText(NewSearch.this,"The Location is outside of the Area", Toast.LENGTH_LONG).show();
}
I am using the JavaGeom 0.11.1 library for finding polygon point. However this code was working exactly fine. Note that myPoints array is an ArrayList<LatLng> of all vertices of the polygons drawn on map. However something happened and now it's working for opposite that is outside of map; if i change !checkPoly then it works fine.
Does anyone know what is wrong?
I looked at the source for the polygon boundary definition. It's using the usual convention for "inside," which requires the vertices to be given in CCW order around the "inside" space. It's likely your boundary is given in CW order, which makes the "inside" what most people would call the outside.
In other words, what you think is a polygon is really a hole in the infinite polygon that covers the whole x-y universe.
So reverse the order of boundary vertices and things should start working as you intend.
ADDITION
If you can't reverse the order of vertices, there is a different polygon membership test that doesn't rely on point order. If you are testing membership of the point (x,y), this algorithm assumes that the point (infinity, y) is outside the polygon and then decides whether (x,y) is on the opposide side. The implementation here in C is due to WR Franklin. It would be easy to port this to Java. I've used it several times with excellent results.
I have been using Google android-maps-utils library and you can make use of the PolyUtil class, particularly at this method:
public static boolean containsLocation(LatLng point, List<LatLng> polygon, boolean geodesic)