Detect swipes algorithm? - java

I want to detect from some 2D points whenever a swipe is made.
The points are coming continuously, they come from a sensor. And are in 2D space, x and y.
Are there any algorithms for this?
I've tried something like this
float totalDistance = 0f;
float totalTime = 0f;
for (int i = points.size - 1; i > 0; i--) {
SwipePoint point1 = points.get(i); // last point added
SwipePoint point2 = points.get(i - 1); // second last point
totalDistance += point1.distance(point2);
if (totalDistance > MIN_SWIPE_DISTANCE
&& totalTime > MIN_SWIPE_TIME) {
// we have a swipe
listener.onSwipe(SwipeType.DOWM, 1f);
points.clear();
return;
}
}
Here i check if the length of the lines is bigger than a constant, and the same for the time, but is not showing anything.
Are there any algorithms for this?
Thanks.

Your algorithm does not seem to identify swipe, and one of the problems is in this line:
totalDistance += point1.distance(point2);
what it does it count total length traveled by a finger and will trigger a "swipe" even if finger travels for long enough with any trajectory.
What you should do is record x and y coordinates of a first point and when you encounter a point that is far enough from a start you can trigger a swipe.
The second problem in your algorithm is that you should check if swipe time is less than maximum swipe time. Also, you doesn't seem to update totalTime anywhere in your code.
The code should look like this (checking only vertical swipe):
SwipePoint startPoint = points.get(points.size - 1);
for (int i = points.size - 2; i > 0; i--) {
SwipePoint point = points.get(i); // last point added
int yDiff = Math.abs(startPoint.getY() - point.getY());
long totalTime = startPoint.getTime() - point.getTime();
if yDiff > MIN_SWIPE_DISTANCE
&& totalTime < MIN_SWIPE_TIME) {
// we have a swipe
listener.onSwipe(SwipeType.DOWM, 1f);
points.clear();
return;
}
}

Related

How to determine if two points do not have any obstructions between them

I am currently trying to put together an algorithm where I can know if there is an obstruction between two defined points in a plane.
Here is an example image.
We can see with the image that point 1, 2, 3, & 6 are all accessible from the origin point. Points 4 and 5 are not. You pass through the polygon.
The code I am using is the following. pStartPoint and pEndPoint is the line from the origin to the point in question. The function checks all edges to see if the line passes through the edge.
public double GetSlopeOfLine(Point a, Point b){
double x = b.y - a.y;
double y = b.x - a.x;
return (x / y);
}
public double GetOffsetOfLine(double x, double y, double slope){
return (y - (slope * x));
}
public boolean IsPointAccessable(Point pStartPoint, Point pEndPoint){
//Define the equation of the line for these points. Once we have slope and offset the equation is
//y = slope * x + offset;
double slopeOfLine = GetSlopeOfLine(pStartPoint, pEndPoint);
double offSet = GetOffsetOfLine(pStartPoint.x, pStartPoint.y, slopeOfLine);
//Collision detection for each side of each obstacle. Once we get the point of collision, does it lie on the
//line in between the two points? If so, collision, and I can't reach that point yet.
for (Iterator<Obstacles> ObstacleIt = AdjustedObstaclesList.iterator(); ObstacleIt.hasNext();) {
Obstacles pObstacle = ObstacleIt.next();
int NumberOfEdges = pObstacle.getPoints().size();
for(int i=0; i<NumberOfEdges; i++){
//Get Edge[i];
int index = i;
Point pFirstPoint = (Point)pObstacle.getPoints().get(index);
if(i >= NumberOfEdges - 1)
index = 0;
else
index = i+1;
Point pNextPoint = (Point)pObstacle.getPoints().get(index);
double slopeOfEdge = GetSlopeOfLine(pFirstPoint, pNextPoint);
double offsetEdge = GetOffsetOfLine(pNextPoint.x, pNextPoint.y, slopeOfEdge);
int x = Math.round((float) ((-offSet + offsetEdge) / (slopeOfLine - slopeOfEdge)));
int y = Math.round((float) ((slopeOfLine * x) + offSet));
//If it lies on either point I could be looking at two adjacent points. I can still reach that point.
if(x > pStartPoint.x && x < pEndPoint.x && y > pStartPoint.y && y < pEndPoint.y &&
x > pFirstPoint.x && x < pNextPoint.x && y > pFirstPoint.y && y < pNextPoint.y){
return false;
}
}
}
return true;
}
If the line passes through and the point where the lines cross is found between pStartPoint and pEndPoint I am assuming that pEndPoint cannot be reached.
This function is not working and I am wondering if it has something to do with the fact that the origin is not at the bottom left but at the top left and that (width, height) of my window is located in the bottom right. Therefore the coordinate plane is messed up.
My mind must be mush because I cannot think how to adjust for this and if that is truly my mistake as I cannot seem to fix the error. I thought adjusting the slope and offset by multiplying each by -1 might have been the solution but that doesn't seem to work.
Is my solution the right one? Does my code seem correct in checking for an intersect point? Is there a better solution to see if a point is accessible.
There is also going to be the next step after this where once I determine what points are accessible if I am now on one of the points of the polygon. For example, from point 1 what points are accessible without crossing into the polygon?
First, I would like to say that using slopes for this kind of task is do-able, but also difficult due to the fact that they are very volatile in the sense that they can go from negative infinity to infinity with a very small change in the point. Here's a slightly different algorithm, which relies on angles rather than slopes. Another advantage of using this is that the coordinate systems don't really matter here. It goes like this (I reused as much of your existing code as I could):
public boolean IsPointAccessable(Point pStartPoint, Point pEndPoint) {
//Collision detection for each side of each obstacle. Once we get the point of collision, does it lie on the
//line in between the two points? If so, collision, and I can't reach that point yet.
for (Iterator<Obstacles> ObstacleIt = AdjustedObstaclesList.iterator(); ObstacleIt.hasNext();) {
Obstacles pObstacle = ObstacleIt.next();
int NumberOfEdges = pObstacle.getPoints().size();
for(int i=0; i<NumberOfEdges; i++){
//Get Edge[i];
int index = i;
Point pFirstPoint = (Point)pObstacle.getPoints().get(index);
if(i >= NumberOfEdges - 1)
index = 0;
else
index = i+1;
Point pNextPoint = (Point)pObstacle.getPoints().get(index);
// Here is where we get a bunch of angles that encode in them important info on
// the problem we are trying to solve.
double angleWithStart = getAngle(pNextPoint, pFirstPoint, pStartPoint);
double angleWithEnd = getAngle(pNextPoint, pFirstPoint, pEndPoint);
double angleWithFirst = getAngle(pStartPoint, pEndPoint, pFirstPoint);
double angleWithNext = getAngle(pStartPoint, pEndPoint, pNextPoint);
// We have accumulated all the necessary angles, now we must decide what they mean.
// If the 'start' and 'end' angles are different signs, then the first and next points
// between them. However, for a point to be inaccessible, it also must be the case that
// the 'first' and 'next' angles are opposite sides, as then the start and end points
// Are between them so a blocking occurs. We check for that here using a creative approach
// This is a creative way of checking if two numbers are different signs.
if (angleWithStart * angleWithEnd <= 0 && angleWithFirst * angleWithNext <= 0) {
return false;
}
}
}
return true;
}
Now, all that is left to do is find a method that calculates the signed angle formed by three points. A quick google search yielded this method (from this SO question):
private double getAngle(Point previous, Point center, Point next) {
return Math.toDegrees(Math.atan2(center.x - next.x, center.y - next.y)-
Math.atan2(previous.x- center.x,previous.y- center.y));
}
Now, this method should work in theory (I am testing to be sure and will edit my answer if I find any issues with signs of angles or something like that). I hope you get the idea and that my comments explain the code well enough, but please leave a comment/question if you want me to elaborate further. If you don't understand the algorithm itself, I recommend getting a piece of paper out and following the algorithm to see what exactly is going on. Hope this helps!
EDIT: To hopefully aid in better understanding the solution using angles, I drew a picture with the four base cases of how the start, end, first, and next could be oriented, and have attached it to this question. Sorry for the sloppiness, I drew it rather quickly, but this should in theory make the idea clearer.
If you have a low segment count (for instance, your example only shows 12 segments for three shapes, two shapes of which we know we can ignore (because of bounding box checks), then I would recommend simply performing line/line intersection checking.
Point s = your selected point;
ArrayList<Point> points = polygon.getPoints();
ArrayList<Edge> edges = polygon.getEdges();
for(Point p: points) {
Line l = new Line(s, p);
for(Edge e: edges) {
Point i = e.intersects(l);
if (i != null) {
System.out.println("collision", i.toString());
}
}
}
With an intersects method that is pretty straight forward:
Point intersects(Line l) {
// boring variable aliassing:
double x1 = this.p1.x,
y1 = this.p1.y,
x2 = this.p2.x,
y2 = this.p2.y,
x3 = l.p1.x,
y2 = l.p1.y,
x3 = l.p2.x,
y2 = l.p2.y,
// actual line intersection algebra:
nx = (x1 * y2 - y1 * x2) * (x3 - x4) -
(x1 - x2) * (x3 * y4 - y3 * x4),
ny = (x1 * y2 - y1 * x2) * (y3 - y4) -
(y1 - y2) * (x3 * y4 - y3 * x4),
d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (d == 0) return null;
return new Point(nx/d, ny/d);
}

Raycasting inaccurately calculating intersections

I am trying to write a raycasting algorithm described in this article. I use a coordinate system where y increases upward, x increases to the left. The variable names in the following code snippet are taken from the article, I will describe them so that the code is easier to read:
rayDirX and rayDirY are coordinates of the vector pointing from the player's position on the map in the direction where the ray is being cast, alpha is the angle between this ray and the origin.
Px, Py are precise coordinates of the player's position on the map
Ax, Ay are the precise coordinates of the first horizontal intersection, later other horizontal intersections.
Bx, By are the precise coordinates of the first vertical intersection, later other vertical intersections.
horXa, horYa, vertXa, vertYb are the step increments, which are constant after finding the first intersection. I suspect that the problem with the algorithm is that these values are not calculated correctly.
mapX, mapY are the coordinates of the lower left corner of an intersection on a map. This is used to check if there is a wall on this position in the array map[][].
Horizontal and vertical intersections are checked alternately. Ax, Ay, or Bx, By should hold the precise position of the intersection.
// Calculate the initial intersections
// Horizontal intersections
// If the ray is facing up
if (rayDirY > 0)
{
horYa = 1;
Ay = mapY+1;
}
// If the ray is facing down
else
{
horYa = -1;
Ay = mapY;
}
horXa = Math.abs(horYa)/tanAlpha;
Ax = Px + (Ay-Py)/tanAlpha;
// Vertical intersections
// If the ray is facing right
if (rayDirX > 0)
{
vertXa = 1;
Bx = mapX+1;
}
// If the ray is facing left
else
{
vertXa = -1;
Bx = mapX;
}
vertYa = Math.abs(vertXa)*tanAlpha;
By = Py + (Px-Bx)*tanAlpha;
//Loop to find where the ray hits a wall
//Number of texture to display
int texNum;
boolean horizontal = Math.abs(Ax * Math.cos(alpha)) < Math.abs(Bx*Math.cos(alpha));
//This loop runs for each ray with the setup above
while(true) {
// Check horizontal intersection
if (horizontal)
{
mapX = (int)Math.floor(Math.abs(Ax));
mapY = (int)Math.floor(Math.abs(Ay));
if(mapX > mapWidth-1) mapX = mapWidth-1;
if(mapY > mapHeight-1) mapY = mapHeight-1;
if(mapX < 0) mapX = 0;
if(mapY < 0) mapY = 0;
texNum = map[mapX][mapY];
if(texNum > 0) break;
Ax += horXa;
Ay += horYa;
horizontal = false;
}
else {
mapX = (int)Math.floor(Math.abs(Bx));
mapY = (int)Math.floor(Math.abs(By));
if(mapX > mapWidth-1) mapX = mapWidth-1;
if(mapY > mapHeight-1) mapY = mapHeight-1;
if(mapX < 0) mapX = 0;
if(mapY < 0) mapY = 0;
texNum = map[mapX][mapY];
if (texNum > 0) break;
Bx += vertXa;
By += vertYa;
horizontal = true;
}
}
Using this algorithm, the image is not rendered properly, see the screenshot. I suspect that it is because of horYa, Ay, vertXa, Bx not being calculated correctly. UPDATE: After some debugging efforts, it seems that sometimes we choose to compute horizontal intersection instead of vertical and vice versa... Really strange!
Can you please spot an error in the algorithm? Thank you for any input!

Make a rectangle move to point B one pixel at a time in a strait line

I have a rectangle which when I hold down the mouse button I want that rectangle to move to that point following a strait line 1 pixel at a time.
This is my code so far (I put comments in it so you can understand)
float distanceX = finalX - x; //the number of pixels needed to get to destination on the X axis
float distanceY = finalY - y; // same as above but Y axis
float moveX = distanceX > 0 ? 1 : -1; // I only want it to move 1 pixel per render
float moveY = distanceY > 0 ? 1 : -1; // same as above
Array<Stuff> collidedX = new Array<Stuff>(); //saves collisions seperately for x and y
Array<Stuff> collidedY = new Array<Stuff>(); //because I want the square to move where the mouse is pointing even if it means only aligning one axis
for (Stuff s : collidables) {
if (overlapsT(s, x + moveX, y)) {
collidedX.add(s);
}
}
if (collidedX.size < 1) {
if (distanceX != 0)
x += moveX;
}
for (Stuff s : collidables) {
if (overlapsT(s, x, y + moveY)) {
collidedY.add(s);
}
}
if (collidedY.size < 1) {
if (distanceY != 0)
y += moveY;
}
right now the problem is it goes perfectly diagonal until it lines up with one of the axis and then moves up down left or right to the destination.
I don't want to move fractions of pixels. The way my custom physics engine works is each pixel matters, fractional pixels are no good so I am trying to figure out how to smooth the path or rather how to decide when to add 1 to x and then y.
Currently I can't comment, so I have to answer. I think the Bresenham's line algorithm will help you out. It's for drawing rasterize lines.
Bresenham

Java game - handling linear movement

So, I'm trying to make a game in LWJGL and it seems to work fine for me. Although, I ran into some issues in moving my entities around on the screen. I want to make it go from one point to another, at the same speed. Also, I'm animating my sprite according to the direction the entity is moving.
But! I have some issues:
1# It flickers because the movement is defined a modifier: delta (to make smooth movement defined by the FPS). Actually, it never really reaches it's point (because it recalculates and never hits the position). How can I solve this?
2# When 2 players join the same server, my character on the fastest computer runs faster. I think it's because of the FPS, how can that be solved?
private String name;
private float positionx,positiony; // Current
private int targetx,targety; // Target
private int dx, dy; // Direction
private int pointx, pointy; // Direction
private float speed;
private Sprite sprite;
public Entity(String name, int positionx, int positiony, Sprite sprite){
this.name = name;
this.speed = 0.1f;
this.positionx = 720;
this.positiony = 450;
this.targetx = 1000; // fix this
this.targety = 10; // this for testing.
this.sprite = sprite;
this.dx = 0;
this.dy = 0;
}
//double distance = Math.sqrt((vx * vx) + (vy * vy));
public void move(long delta){
if(positionx < targetx){
dx = 1;
pointx = 1;
}else if(positionx > targetx){
dx = -1;
pointx = -1;
}else{
dx = 0;
}
if(positiony < targety){
dy = 1;
pointy = 1;
}else if(positiony > targety){
dy = -1;
pointy = -1;
}else{
dy = 0;
}
//Set animations:
if(positionx==targetx && positiony==targety){
if(pointx<0){
sprite.setAnimation(5, 2, 100); // Standing left
}else if(pointx>0){
sprite.setAnimation(6, 2, 100); // Standing right
}else if(pointy<0){
sprite.setAnimation(7, 2, 100); // Standing up
}else if(pointy>0){
sprite.setAnimation(4, 2, 100); // Standing down
}
}else{
if(pointx<0){
sprite.setAnimation(1, 2, 100); // Walking left
}else if(pointx>0){
sprite.setAnimation(2, 2, 100); // Walking right
}else if(pointy<0){
sprite.setAnimation(3, 2, 100); // Walking up
}else if(pointy>0){
sprite.setAnimation(0, 2, 100); // Walking down
}
}
//movement here.
positionx += dx*delta*speed;
positiony += dy*delta*speed;
System.out.println(dx*delta*speed);
sprite.setPosition((int)positionx, (int)positiony);
}
1# It flickers because the movement is defined a modifier: delta (to make smooth movement defined by the FPS). Actually, it never really reaches it's point (because it recalculates and never hits the position). How can I solve this?
If you store point A and point B between which it moves, you can set a time interval. Each time interval a set distance will be travelled and if at one iteration the object goes too far you can set its coordinates for point B. This can be easily done with a Timer. That way, after a certain amount of time, it will be on your specified position.
2# When 2 players join the same server, my character on the fastest computer runs faster. I think it's because of the FPS, how can that be solved?
Same answer as question #1, if you use a Timer. Each player will move at the same speed (because the elapsed time is the same for each gamer).
Bottom line:
fps is variable, while elapsed time is the same for everyone.

Divide a 2D path created from points XY into equal chunks Java

I have an array of points A,B,C,D,E...N which when connected make a path.
How can i divide this path to equal chunks and get position of each chunk XY ?
EDIT : As user Hedja suggested i have created function to process this problem, but i cannot detect situation where chunk is splitted on two subpaths
public ArrayList<PointF> getPositions(ArrayList<PointF> mInput,float mChunkSize){
ArrayList<PointF> mResult = new ArrayList<PointF>();
float mModulo = 0f;
for (int i = 0;i<mInput.size()-1;i++){
//distance to next
float mDistanceAB = MyGameMath.distance(mInput.get(i).x, mInput.get(i).y,mInput.get(i+1).x,mInput.get(i+1).y);
//how many parts will fit
float mCountParts = (float) (mDistanceAB/mChunkSize); //how much parts will fit
//if distance is greater than chunk size
if (Math.abs(mDistanceAB)>=mChunkSize) {
Log.i("Chunk","Index "+(i)+" -> "+(i+1)+" = "+mCountParts+", rest="+mModulo);
float dx = mInput.get(i+1).x-mInput.get(i).x;
float dy = mInput.get(i+1).y-mInput.get(i).y;
float ux = dx/mDistanceAB;
float uy = dy/mDistanceAB;
for (int y=0;y<=mCountParts;y++){
//for every part
float nx = mInput.get(i).x+ux*mChunkSize*y;
float ny = mInput.get(i).y+uy*mChunkSize*y;
//Log.i("Chunk","at:"+nx+","+ny);
mResult.add(new PointF(nx, ny));
}
}
mModulo = mDistanceAB%mChunkSize; //how much left from previous subpath
}
return mResult;
}
So I assume you have something similar to this where Point is an object with attributes x and y.
Point[] points = new Points[]{ //Your Points }
List<Point> chunkedPoints = new ArrayList<Point>();
I also assume by "equal chunks" you mean the distance of each path.
First you'll iterate through the array, as you won't need to calculate the "next point" after the last point, you can add it at the end.:
for(int i = 0; i < points.length-1; i++) { //Skip the last element
//chunking here
}
chunkedPoints.add(points[points.length-1]); //Add the last element
You'll need to find the Unit Vector, that is, the direction you travel to get to the next point. So first you need to get the difference in x and y from one point and the next:
double dx = point[i].x - point[i+1].x;
double dy = point[i].y - point[i+1].y;
Then the distance from that point to the next (simple Pythagoras):
double distance = Math.sqrt(dx*dx+dy*dy);
The unit vector can now be calculated
double ux = dx/distance;
double uy = dy/distance;
So now you know where to travel, you need to specify how far you want to travel along it, I'll call this CHUNK_SIZE.
double nx = point[i].x + ux*CHUNK_SIZE;
double ny = point[i].y + uy*CHUNK_SIZE;
nx and ny is the co-ordinate of your new point. However, you need to check if you've passed the next point so that you can stop. Your problem doesn't specify what you do when you reach an end of a subpath without travelling the chunk size so I'll assume you simply stop at it, so the code becomes:
double nx = point[i].x;
double ny = point[i].y;
for(
//This part can be tidier
int count = 0;
count < CHUNK_SIZE && nx+ux != points[i+1].x && ny+uy != points[i+1].y;
count++
) {
nx += ux;
ny += uy;
}
Point newPoint = new Point(nx, ny);
Now you have your new Point, you can start from there, aim for the same point as before or if it's the same as the next point, start from the point after that. So your loop is now something like
chunkedPoints.add(points[0]);
for(int i = 0; i < points.length-1; i++) { //Skip the last element
Point newPoint;
do {
//chunking
newPoint = new Point(nx, ny);
chunkedPoints.add(newPoint);
} while(!newPoint.equals(points[i+1]));
}
chunkedPoints.add(points[points.length-1]); //Add the last element
Hope that helped.
I haven't tested this, but I've done something very similar in the past, so it should work.
EDIT: Okay, I've seen your edit and honestly have no idea what your question is asking. Sorry.

Categories

Resources