I'm working on some artificial intelligence, and I want to be able for my AI not to run into given coordinates as these are references of a wall/boundary.
To begin with, every time my AI hits a wall, it makes a reference to that position (x, y). When it hits the same wall three times, it uses linear check points to 'imagine' there is a wall going through these coordinates.
I want to now prevent my AI from going into that wall again.
To detect if my coordinates make a straight line, I use:
private boolean collinear(double x1, double y1, double x2, double y2, double x3, double y3) {
return (y1 - y2) * (x1 - x3) == (y1 - y3) * (x1 - x2);
}
This returns true is the given points are linear to one another.
So my problems are:
How do I determine whether my robot is approaching the wall from its current trajectory?
Instead of Java 'imagining' there's a line from 1, to 3. But to 'imagine' a line all the way through these linear coordinantes, until infinity (or close).
I have a feeling this is going to require some confusing trigonometry?
For #2, you could check if the slope between any point and one point on the wall/line you want, is the same as the slope between two points on the line.
private boolean onWall(double x, double y, double wallX1, double wallY1, double wallX2, double wallY2) {
return (wallY1 - y) / (wallX1 - x) == (wallY2 - wallY1) / (wallX2 / wallX1);
}
So, the slopes calculated share a point, so if they're the same, they're all on the same line.
Interesting problem. Well two appraoches come to my mind:
So what you can do is that, once every line is detected, store its slope m and line constatnt c as per line y= mx +c. So once you change your co-ordinate to a new co-ordinate. put your new (x1,y1) in above line equation to see if y1 == m*x1 + c. The whole operation will be computationally expensive as O(n) where n is number of lines detected for every new co-ordinate movement
You can reduce the above by clustering points and checking the line matching as per cluster rather than for every line. i.e. store what all lines pass through a cluster and check only for those lines when you are currently in the respective cluster. This should be an ideal solution
Another solution would be to have an imaginary circle of radius r around your current point. Once the circle is obtained, find what all lines pass through the current cluster (as per explained above). For every new movement, check wall or not only for those lines. Once you move out of your cluster, draw a new circle again
I think this problem is more suitable for programmers.stackexchange.com rather than here :)
Related
This is my solution to this question:
Given a circle represented as (radius, x_center, y_center) and an
axis-aligned rectangle represented as (x1, y1, x2, y2), where (x1, y1)
are the coordinates of the bottom-left corner, and (x2, y2) are the
coordinates of the top-right corner of the rectangle.
Return True if the circle and rectangle are overlapped otherwise
return False.
In other words, check if there are any point (xi, yi) such that
belongs to the circle and the rectangle at the same time.
class Solution {
public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {
for(int i=x1; i<=x2; ){
for(int j=y1; j<=y2; ){
System.out.println((Math.pow(i-x_center, 2) +" "+ Math.pow(j-y_center, 2))+" "+Math.pow(radius, 2));
System.out.println(i+" "+j);
if((Math.pow(i-x_center, 2)+Math.pow(j-y_center, 2))<=Math.pow(radius, 2)){
return true;
}
j += 1;
}
i += 1;
}
return false;
}
}
I am pretty confident that the logic is correct. Ranging from the bottom left corner of the rectangle to the top right point, for every point, I am checking if it lies inside the circle.
If I increase the increment step to anything beyond '1', I see that the code fails for the test cases where the rectangle and circle just 'touch' each other. But having it this way leads to exceeding the time limit in some cases. How do I optimize the code for this logic?
Thanks in advance.
This problem can be simplified. I've found a solution of time complexity O(1) and memory complexity O(1). Instead of checking for every single pixel from the rectangle, you can even only take into consideration the bounds themselves.
As I see it, there are 3 cases:
Circle is fully inside rectangle.
Rectangle is fully inside circle
Circle and rectangle outlines intersect in at least one point. This is the tougher one.
I'll call center of the circle coordinates x0 and y0.
You can simply check the bounding box for the circle, as in, which is the northern most point of the circle(x0,y0-radius), which is the southern-most point of the circle(x0,y0+radius), eastern-most(x0-radius,y0) and western-most(x0+radius,y0). If they all fall within the rectangle, then problem solved.
If a rectangle is fully within a circle, that definitely means that its corners are at a smaller distance from the center of the circle than the radius. Simply check this distance for each corner.
Now comes the hard part.
So, as you have figured out, being in a circle(or intersecting one) means that some point must be at a smaller or equal distance from the center than the radius.
However, we can do an optimization for the rectangle checking part, too. Intersection with a rectangle likely means intersection with at least one of the segments that make the outline of the rectangle. So, in the case of an intersection between a rectangle and a circle, you need to check if there is any segment that would be at a smaller or equal distance from the center of the circle than the radius.
Edit: Also, the reason that your code fails on tests where they barely touch is likely due to floating-point errors. Do not use == (or in this case <=, which is similar) for checking if two floating point(or even a floating-point and integer) values are the same. Math.pow() in Java returns double. Just use normal multiplication for squaring.
In fact, you might want to stay as far from floating-point as possible, unless you can't figure out how to get rid of them and the problem says "0.001 error is acceptable" or something around the lines. They are both slow and prone to errors.
Edit 2: Also, I've written the code to help you aid in understanding this explanation. I've tested it on the site, it works for every test with runtime 1ms and memory usage 37.7Mb.
class Solution {
public boolean checkOverlap(int radius, int x_center, int y_center, int x1, int y1, int x2, int y2) {
//case 1: circle is fully inside rectangle
//check the bounding box of the circle against the rectangle
if(x_center-radius>=x1&&y_center-radius>=y1
&&x_center+radius<=x2&&y_center+radius<=y2
)
return true;
//case 2: checking closest corner against circle bounds
int minX=(Math.abs(x_center-x1)>Math.abs(x_center-x2))?(x_center-x2):(x_center-x1);
int minY=(Math.abs(y_center-y1)>Math.abs(y_center-y2))?(y_center-y2):(y_center-y1);
if(minX*minX+minY*minY<=radius*radius)
return true;
//case 3: checking distances to segments against circle bounds
//Checking distance from a segment to a point is alike checking
//the distance from the line the segment is part of to a point,
//except you have to check if the closest point from the segment
//is actually on the segment. If it isn't, the distance from a
//segment to a point is the minimum distance from one of its
//corners to the point.
if(x1<=x_center&&x_center<=x2)
if(minY*minY<=radius*radius)
return true;
if(y1<=y_center&&y_center<=y2)
if(minX*minX<=radius*radius)
return true;
return false;
}
}
This code could be possibly shortened. However, time complexity-wise, it can't get better than O(1).
I'm trying to write a java mobile application (J2ME) and I got stuck with a problem: in my project there are moving circles called shots, and non moving circles called orbs. When a shot hits an orb, it should bounce off by classical physical laws. However I couldn't find any algorithm of this sort.
The movement of a shot is described by velocity on axis x and y (pixels/update). all the information about the circles is known: their location, radius and the speed (on axis x and y) of the shot.
Note: the orb does not start moving after the collision, it stays at its place. The collision is an elastic collision between the two while the orb remains static
here is the collision solution method in class Shot:
public void collision(Orb o)
{
//the orb's center point
Point oc=new Point(o.getTopLeft().x+o.getWidth()/2,o.getTopLeft().y+o.getWidth()/2);
//the shot's center point
Point sc=new Point(topLeft.x+width/2,topLeft.y+width/2);
//variables vx and vy are the shot's velocity on axis x and y
if(oc.x==sc.x)
{
vy=-vy;
return ;
}
if(oc.y==sc.y)
{
vx=-vx;
return ;
}
// o.getWidth() returns the orb's width, width is the shot's width
double angle=0; //here should be some sort of calculation of the shot's angle
setAngle(angle);
}
public void setAngle(double angle)
{
double v=Math.sqrt(vx*vx+vy*vy);
vx=Math.cos(Math.toRadians(angle))*v;
vy=-Math.sin(Math.toRadians(angle))*v;
}
thanks in advance for all helpers
At the point of collision, momentum, angular momentum and energy are preserved. Set m1, m2 the masses of the disks, p1=(p1x,p1y), p2=(p2x,p2y) the positions of the centers of the disks at collition time, u1, u2 the velocities before and v1,v2 the velocities after collision. Then the conservation laws demand that
0 = m1*(u1-v1)+m2*(u2-v2)
0 = m1*cross(p1,u1-v1)+m2*cross(p2,u2-v2)
0 = m1*dot(u1-v1,u1+v1)+m2*dot(u2-v2,u2+v2)
Eliminate u2-v2 using the first equation
0 = m1*cross(p1-p2,u1-v1)
0 = m1*dot(u1-v1,u1+v1-u2-v2)
The first tells us that (u1-v1) and thus (u2-v2) is a multiple of (p1-p2), the impulse exchange is in the normal or radial direction, no tangential interaction. Conservation of impulse and energy now leads to a interaction constant a so that
u1-v1 = m2*a*(p1-p2)
u2-v2 = m1*a*(p2-p1)
0 = dot(m2*a*(p1-p2), 2*u1-m2*a*(p1-p2)-2*u2+m1*a*(p2-p1))
resulting in a condition for the non-zero interaction term a
2 * dot(p1-p2, u1-u2) = (m1+m2) * dot(p1-p2,p1-p2) * a
which can now be solved using the fraction
b = dot(p1-p2, u1-u2) / dot(p1-p2, p1-p2)
as
a = 2/(m1+m2) * b
v1 = u1 - 2 * m2/(m1+m2) * b * (p1-p2)
v2 = u2 - 2 * m1/(m1+m2) * b * (p2-p1)
To get the second disk stationary, set u2=0 and its mass m2 to be very large or infinite, then the second formula says v2=u2=0 and the first
v1 = u1 - 2 * dot(p1-p2, u1) / dot(p1-p2, p1-p2) * (p1-p2)
that is, v1 is the reflection of u1 on the plane that has (p1-p2) as its normal. Note that the point of collision is characterized by norm(p1-p2)=r1+r2 or
dot(p1-p2, p1-p2) = (r1+r2)^2
so that the denominator is already known from collision detection.
Per your code, oc{x,y} contains the center of the fixed disk or orb, sc{x,y} the center and {vx,vy} the velocity of the moving disk.
Compute dc={sc.x-oc.x, sc.y-oc.y} and dist2=dc.x*dc.x+dc.y*dc.y
1.a Check that sqrt(dist2) is sufficiently close to sc.radius+oc.radius. Common lore says that comparing the squares is more efficient. Fine-tune the location of the intersection point if dist2 is too small.
Compute dot = dc.x*vx+dcy*vy and dot = dot/dist2
Update vx = vx - 2*dot*dc.x, vy = vy - 2*dot*dc.y
The special cases are contained inside these formulas, e.g., for dc.y==0, that is, oc.y==sc.y one gets dot=vx/dc.x, so that vx=-vx, vy=vy results.
Considering that one circle is static I would say that including energy and momentum is redundant. The system's momentum will be preserved as long as the moving ball contains the same speed before and after the collision. Thus the only thing you need to change is the angle at which the ball is moving.
I know there's a lot of opinions against using trigonometric functions if you can solve the issue using vector math. However, once you know the contact point between the two circles, the trigonometric way of dealing with the issue is this simple:
dx = -dx; //Reverse direction
dy = -dy;
double speed = Math.sqrt(dx*dx + dy*dy);
double currentAngle = Math.atan2(dy, dx);
//The angle between the ball's center and the orbs center
double reflectionAngle = Math.atan2(oc.y - sc.y, oc.x - sc.x);
//The outcome of this "static" collision is just a angular reflection with preserved speed
double newAngle = 2*reflectionAngle - currentAngle;
dx = speed * Math.cos(newAngle); //Setting new velocity
dy = speed * Math.sin(newAngle);
Using the orb's coordinates in the calculation is an approximation that gains accuracy the closer your shot is to the actual impact point in time when this method is executed. Thus you might want to do one of the following:
Replace the orb's coordinates by the actual point of impact (a tad more accurate)
Replace the shot's coordinates by the position it has exactly when the impact will/did occur. This is the best scenario in respect to the outcome angle, however may lead to slight positional displacements compared to a fully realistic scenario.
I am trying to compute a polygon that surrounds a line connecting multiple points (e.g. a GPX track).
The image below shows an example with the track as red line and the desired polygon in blue.
As simplification the red points are denoted by x and y - not by latitude/longitude.
How do I compute such an environment (light blue polygon) if I only have the list of the three points specifying the path?
Partial solutions (e.g. for only two points) or hints about mathematical libraries (in Java) that provide algorithms for such a computation would also bring me one step forward.
Further assumptions:
The track is intersection free.
Update:
Using the approach as presented by Rogach and xan I ran into some problems if the angle between the lines is smaller than 90 degree or larger than 270 degree:
As you can see the polygon gets intersects itself which leads to a serious problem.
From my point of view using an java.awt.geom.Area is the better approach:
My solution (based on the code by Rogach):
For each line connecting two points of the track I compute a surrounding polygon. Afterwards I add (area union) the computed polygon to an Area which does all the necessary computation for me. As the Area strictly uses the "or" algorithm on adding new polygons I do not have to care about "self intersections" of the polygon as presented in the update above.
Area area = new Area();
for (int i = 1; i < points.size(); i++) {
Point2D point1 = points.get(i - 1);
Point2D point2 = points.get(i);
Line2D.Double ln = new Line2D.Double(point1.getX(), point1.getY(), point2.getX(), point2.getY());
double indent = 15.0; // distance from central line
double length = ln.getP1().distance(ln.getP2());
double dx_li = (ln.getX2() - ln.getX1()) / length * indent;
double dy_li = (ln.getY2() - ln.getY1()) / length * indent;
// moved p1 point
double p1X = ln.getX1() - dx_li;
double p1Y = ln.getY1() - dy_li;
// line moved to the left
double lX1 = ln.getX1() - dy_li;
double lY1 = ln.getY1() + dx_li;
double lX2 = ln.getX2() - dy_li;
double lY2 = ln.getY2() + dx_li;
// moved p2 point
double p2X = ln.getX2() + dx_li;
double p2Y = ln.getY2() + dy_li;
// line moved to the right
double rX1_ = ln.getX1() + dy_li;
double rY1 = ln.getY1() - dx_li;
double rX2 = ln.getX2() + dy_li;
double rY2 = ln.getY2() - dx_li;
Path2D p = new Path2D.Double();
p.moveTo(lX1, lY1);
p.lineTo(lX2, lY2);
p.lineTo(p2X, p2Y);
p.lineTo(rX2, rY2);
p.lineTo(rX1_, rY1);
p.lineTo(p1X, p1Y);
p.lineTo(lX1, lY1);
area.add(new Area(p));
}
As I see, this problem is similar to polygon buffering problem.
I think following approach can help you:
For each segment of your track, find two lines - one to the left and one to the right.
Then, iterate for over your ofsetted lines, and resolve intersections. For example:
http://img25.imageshack.us/img25/7660/temprhk.png
Add caps to ends, and you're done! :)
And some code:
Moving a line to the left:
Line2D l;
double indent; // distance from central line
double dx = ln.getX2() - ln.getX1();
double dy = ln.getY2() - ln.getY1();
double length = ln.getP1().distance(ln.getP2());
double newX1 = l.getX1() - indent*(dy/length);
double newY1 = l.getY1() + indent*(dx/length);
double newX2 = l.getX2() - indent*(dy/length);
double newY2 = l.getY2() + indent*(dx/length);
Line2D leftLine = new Line2D.Double(newX1, newY1, newX2, newY2);
For moving it to the right, change "+" to "-" and vice versa in the last 4 lines of code.
About working with intersections - if two line segment intersect, you just output the intersection point. If they do not, then situation is a bit more complicated - you can, of course, still output the intersection, but in case of rapidly turning track, there will be strange outbursts. I inserted an arc segment in similar situation, but the code is to big and scattered, so I can't paste it here.
Or, you can do as you show on your picture - just connect end points.
And, by the way, if speed is not a big issue, you can use even better way - for each line of track, find left and right lines, add caps, pack it all into Path2D, then create Area from Path2D.
In such case, you can make this "line with caps" as intersection of three areas: rectangle, whose points are just end points of right and left line, and two circles with centers on original track segment ends.
When you compute Areas for all lines, just intersect them using Area add() method.
This approach deals with just any situations, even self-intersections and breaks in the track.
See my answer to a similar question, "How to draw an outline around any line."
Same idea as Rogach provides here, but perhaps different drawings and explanations will help clarify it.
If you don't want to write the code for the buffering as described by Rogach, JTS could do the magic for you.
See the developer guide for a quick introduction.
Half-baked suggestion: Calculate the normal to each segment. Then, for each vertex V_i, interpolate the normals from its adjacent segments to get n_i (normalise it again) and add two vertices at V_i +/- a*n_i where a is some scaling factor.
If you join these points, you won't get exactly your blue polygon, but it might be good enough.
You may have to keep track of which "side" the new vertices are on. If you can close the curve without self-intersections this just becomes a point in polygon test for each vertex.
How could I draw a quadratic curve or a trigonometric curve (such as sin(x)) on a Canvas?
Like you, I needed to draw a curved line from point(x1, y1) to point (x2, y2). I did some searching around which lead me to the Path class (android.graphics.Path). Path has numerous methods for drawing lines. Once you have created a path you use a draw method to make the actual line. The paths can be rotated, transformed, saved, and added to. There are arcs, circles, and rectangles that be drawn with this class too.
http://developer.android.com/reference/android/graphics/Path.html
Set start point of path โ mPath.moveTo(x1, y1);
Set constant and end points โ mPath.quadTo(cx, cy, x2, y2);
Convert path to line โ canvas.drawPath(mPath, mPaint);
Here is a drawEquation() method I wrote for a Graph class - I think it may help. The basic idea to create a method that accepts an equation (which is basically just a function) like
function(x) = Math.sin(x);
and then loop through the bounds of the graph and draws small segments connecting each point. The transformContext() just inverts the canvas context so that increasing values of y go upwards and not downwards:
Graph.prototype.transformContext = function(){
var canvas = this.canvas;
var context = this.context;
// move context to center of canvas
this.context.translate(this.centerX, this.centerY);
// stretch grid to fit the canvas window, and
// invert the y scale so that that increments
// as you move upwards
context.scale(this.scaleX, -this.scaleY);
};
Graph.prototype.drawEquation = function(equation, color, thickness){
var canvas = this.canvas;
var context = this.context;
context.save();
this.transformContext();
context.beginPath();
context.moveTo(this.minX, equation(this.minX));
for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
context.lineTo(x, equation(x));
}
context.restore();
context.lineJoin = "round";
context.lineWidth = thickness;
context.strokeStyle = color;
context.stroke();
};
Most drawing APIs dont provide such functions, you will have to calculate the pixels of your desired curve in pixels and draw piece by piece on the canvas using one or more calls to the canvas API.
Use Canvas.drawPath and Path.quadTo.
I'm going to assume that you are familiar with drawing basic lines on a canvas, if not then respond back and we can delve further back. However, as far as just drawing a sine function there is a function within the Math class that has just what you need.
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Math.html#sin%28double%29
From there you just need to pass your x variable(in radians) into the function and save it's output as a y variable. This represent a point on your graph. Now increment the x1 variable by a small amount (perhaps 1/100 of your graph, though you will need to adjust this to taste), run it through the function again and save those variables(x2 and y2) as your second point. Draw a line between these two points. Save your x2,y2 variables as x1, y1 and increment your x value again to find the third point, so on and so forth. This is not a "true" curve as it is really just a series of lines which approximate the function, a calculus approach if you will.
So:
x1 = x; // where x is some point on the x axis which you would like to start graphing at.
y1 = sin(x);
x2 = x1 + increment;
y2 = sin(x2);
//Draw a line here
x1 = x2;
y1 = y2;
//return to top, this code would obviously be in a loop in which uses increment as it's own increment with the initial value being equal to the amount you want to increment each time(let's say....5) and the "next" statement being increment = increment + 5.
There is also a GraphCanvas class which I am unfamiliar with which appears to take those same points and draw the curve between them, though I am unsure what sort of transform is being used to draw the curve and how accurate that is. Here is the Class:
http://www.java2s.com/Code/Java/Swing-Components/GraphCanvas.htm
What is the best way to go about moving a Point2D.Double x distance closer to another Point2D.Double?
Edit: Tried to edit, but so went down for maintenance. No this is not homework
I need to move a plane (A) towards the end of a runway (C) and point it in the correct direction (angle a).
alt text http://img246.imageshack.us/img246/9707/planec.png
Here is what I have so far, but it seems messy, what is the usual way to go about doing something like this?
//coordinate = plane coordinate (Point2D.Double)
//Distance = max distance the plane can travel in this frame
Triangle triangle = new Triangle(coordinate, new Coordinate(coordinate.x, landingCoordinate.y), landingCoordinate);
double angle = 0;
//Above to the left
if (coordinate.x <= landingCoordinate.x && coordinate.y <= landingCoordinate.y)
{
angle = triangle.getAngleC();
coordinate.rotate(angle, distance);
angle = (Math.PI-angle);
}
//Above to the right
else if (coordinate.x >= landingCoordinate.x && coordinate.y <= landingCoordinate.y)
{
angle = triangle.getAngleC();
coordinate.rotate(Math.PI-angle, distance);
angle = (Math.PI*1.5-angle);
}
plane.setAngle(angle);
The triangle class can be found at http://pastebin.com/RtCB2kSZ
Bearing in mind the plane can be in in any position around the runway point
You can minimize the difference along both axis by a percent (that depends on how much you want to move the points).
For example:
Point2D.Double p1, p2;
//p1 and p2 inits
// you don't use abs value and use the still point as the first one of the subtraction
double deltaX = p2.getX() - p1.getX();
double deltaY = p2.getY() - p1.getY();
// now you know how much far they are
double coeff = 0.5; //this coefficient can be tweaked to decice how much near the two points will be after the update.. 0.5 = 50% of the previous distance
p1.setLocation(p1.getX() + coeff*deltaX, p1.getY() + coeff*deltaY);
So you moved p1 halfway toward p2. The good thing avoid abs is that, if you choose which point will be moved and which one will stand still you can avoid if tests and just use the raw coefficient.
The shortest distance between two points is a line, so simply move that point x units along the line that connects the two points.
Edit: I didn't want to give away the specifics of the answer if this is homework, but this is simple enough that it can be illustrated without being too spoiler-y.
Let us assume you have two points A = (x1, y1) and B = (x2, y2). The line that includes these two points has the equation
(x1, y1) + t ยท (x2 - x1, y2 - y1)
where t is some parameter. Notice that when t = 1, the point specified by the line is B, and when t = 0, the point specified by the line is A.
Now, you would like to move B to B', a point which is a new distance d away from A:
A B' B
(+)---------------------(+)-----------(+)
<========={ d }=========>
The point B', like any other point on the line, is also governed by the equation we showed earlier. But what value of t do we use? Well, when t is 1, the equation points to B, which is |AB| units away from A. So the value of t that specifies B' is t = d/|AB|.
Solving for |AB| and plugging this into the above equation is left as an exercise to the reader.
Vectors to the rescue!
Given points A and B. Create a vector V from A to B (by doing B-A). Normalize vector V into a unit vector and then just multiply it with the distance, d, you want and finally add the resulting vector to point A. ie:
A_moved = A + |(B-A)|*d
Java(ish)
Vector2D a_moved = a.add(b.subtract(a).norm().multiply(d));
No angles, no nasty trig needed.
double angle = Math.atan2(landingCoordinate.y-coordinate.y, landingCoordinate.x-coordinate.x);
coordinate.x += Math.cos(angle)*distance;
coordinate.y += Math.sin(angle)*distance;
//Add 90 degress to the plane angle
plane.setAngle(angle + 1.57079633);
(point A is to be moved closer to B)
if (A.x > B.x)
//decrement A.x
if (A.x < B.x)
//increment A.x
that might be the basic idea in pseudocode, but there's a lot more to it than that. How do you define 'best' way?
Certain things need to be considered:
Is there a specific measure/ratio you want the points to be apart from each other, or do you just want them closer?
Should both coordinates always be modified? (e.g. if you want to move (1,50) closer to (0,0), do you make it (.5, 25) or just (1,25)?
if the point is to be 1 unit away, should it be 1 unit horizontally? directly diagonally? 1 unit away on the line between the 2 points?
Give us a little more detail and we'll see what we've got. :D
In this game, integral coordinates are used to represent squares in a grid. The method move(int row, int col) moves toward the specified row and column by advancing one square in one of eight semi-cardinal directions, as seen here.