I have a little issue with my Collision Detection System for a Game.
In the game are several structures which connect to each other. However they should not connect when there is another structure in between them.
For some weird reason it sometimes fails to connect to directly adjacent structures when there is a structure in a direct line behind them. Rarely it produces other weird connections.
Picture:
The red marked nodes are supposed to be connected.
Code:
public void drawConnections(Graphics g) {
ArrayList<EnergyContainer> structurecopy = (ArrayList<EnergyContainer>) Mainclass.structures.clone(); //all structures in a list
structurecopy.remove(this); //as we are member of the list
structurecopy.removeIf(t -> (!hasStructureInRangeWithoutObstaclesInBetween(t)));
structurecopy.removeIf(t -> !t.receivesEnergyfromNeighbors()); //unimportant check if it is allowed to connect (its working)
structurecopy.forEach(t -> drawConnectionTo(t, g)); //also works fine
}
public boolean hasStructureInRangeWithoutObstaclesInBetween(Structure structureWhichShouldBeInRange) {
// if in Range
if (getRange() >= Math.hypot(structureWhichShouldBeInRange.getX() - getX(),
structureWhichShouldBeInRange.getY() - getY())){ //checks if structure is in range
ArrayList<EnergyContainer> structureclone = (ArrayList<EnergyContainer>) Mainclass.structures.clone();
structureclone.remove(this); //again removes itself from the list
structureclone.remove(structureWhichShouldBeInRange); //also removes target - so it doesn't block itself
structureclone.removeIf(t -> !t.collidesWithLine(this.getX(), structureWhichShouldBeInRange.getX(),
this.getY(), structureWhichShouldBeInRange.getY())); //removes it when it does not collide
return structureclone.size() == 0; //returns true when no collisions are found
}
return false;
}
public boolean collidesWithLine(int x1, int x2, int y1, int y2) {
// Line Segment - Circle Collision Detection
double dx = x2 - x1;
double dy = y2 - y1;
double a = dx * dx + dy * dy; //this is the distance
double b = 2 * dx * (x1 - getX()) + 2 * dy * (y1 - getY());
double c = getX() * getX() + getY() * getY() + x1 * x1 + y1 * y1 - 2 * (getX() * x1 + getY() * y1)
- getCollisionRadius() * getCollisionRadius();
double discriminant = b * b - 4 * a * c;
return discriminant >= 0; // no intersection -> discriminant <0
}
(I added the comments for this text only, so please ignore them if they'd cause compile errors).
Can someone tell me what I am doing wrong?
There might be a couple problems here:
First: As Marat stated: b may be return a value of 0. This is would be happening if your getX() and getY() are returning x1 and y1. If that's the case, you are essentially doing this: (2dx * 0) + (2dy * 0). If that's the case, it can negatively impact your later equations.
Secondly: More than likely, you are ALWAYS returning true from this courtesy of your final equation:
double discriminant = b * b - 4 * a * c;
//This breaks down to discriminant = b^2 * 4ac
Even if b is 0 at this point, as long as either a or c have a value greater than 0, return discriminant >= 0; will be true;
I would HIGHLY recommend putting a breakpoint in at the 2 parts I mentioned and check your values prior to and after the code executing so you can see what's going on with the math.
Also, the Unity API has collision detection functions. You should look in to that. https://docs.unity3d.com/Manual/PhysicsSection.html
Hope that helps.
Assumption:
1 If I understand correctly, these are methods of some Structure class.
2 hasStructureInRangeWithoutObstaclesInBetween is the only caller of collidesWithLine or at least that's how the question is presented.
Because of (2) b is always 0.
I have a feeling it was not your intention. Please revisit you collidesWithLine method.
Related
I am coding a game and want a projectile to go from one location to the next moving at intervals every frame.
I've been playing around with the slope-intercept method of determining things and I'm getting close, but I am stuck.
Here is my code so far:
animationFrame = refresh;
double x, y, xPerF; //Values for drawing
double m, b; //Value for slope and y-intercept
double x1, x2, y1, y2; //Values for the targets
x1 = getCenterX();
x2 = Canvas.target[shotTarget].getCenterX();
y1 = getCenterY();
y2 = Canvas.target[shotTarget].getCenterY();
xPerF = Point2D.distance(x1, y1, x2, y2)/animationSpeed;
//Calculate slope
if(x2>x1) m = (y2-y1)/(x2-x1);
else if(x2<x1) m = (y1-y2)/(x1-x2);
else m = 0;
//Calculate the y-intercept
b = m * x1 - y1;
if(b<0) b = -b + Canvas.myHeight;
else {
b -= Canvas.myHeight;
if(b<0) b = -b;
}
//Calculate the x value
if(x1>x2) x = x1 - (xPerF * animationFrame);
else if(x1<x2) x = x1 + (xPerF * animationFrame);
else x = x1;
//Calculate the y value
if(m!=0) y = (m * x + b) - Canvas.myHeight;
else {
if(y1>y2) y = y1 - (xPerF * animationFrame);
else y = y1 + (xPerF * animationFrame);
}
g.fillOval((int) x - 15, (int) y - 15, 30, 30);
//Debugging
System.out.println("Frame " + animationFrame + " of " + animationSpeed + " | " + y + " = " + m + " * " + x + " + " + b + " | at speed of " + xPerF);
Updated
I expect the animation to end at the target location, but it always either overshoots or is right on target. It mainly overshoots when the target is pretty kind of straight above the tower, give or take a few x co-ordinates. I have worked this out to be a quadrant 1 x-y plane and I believe the problem I have now lies with how I am calculating my slope. Thanks!
Outdated
Here is a mini applet to demonstrate: https://drive.google.com/file/d/1fCTFJzulY1fcBUmdV6AXOd7Ol1g9B3lo/view?usp=sharing
Click on each target to target it
I believe your approach is fundamentally flawed. It is prone to rounding errors which might be a source for overshoots. It is also hard to make work well under real world where your application is not the only one so CPU might be in high demand and some frames might be skipped, and so on. The better approach is to use time rather than frames as the main driver of the events. Your main method drawScene accepts current time as one of its arguments. When any animation starts, you save the time when it started. Then, the job becomes much easier. For example for linear animation it would be something like this:
double animationPart = (currentTime - animationStartTime) / totalAnimationDuration;
// fix rounding error
if (animationPart > 1.0)
animationPart = 1.0;
double xCur = xStart * (1.0 - animationPart) + xEnd * animationPart;
double yCur = yStart * (1.0 - animationPart) + yEnd * animationPart;
P.S. the "time" doesn't have to be real time, it might be some other "game time" if it somehow makes more sense but still this approach is IMHO much easier to implement correctly.
Update
I'd say that the overall code quality is rather bad. Concerns are badly separated, there are a lot of magic numbers, and global static things. For example, having to two bullets in flight will be not easy to implement in this code.
There are also some real bugs in animation code. Some obvious bugs are:
xPerF is calculated wrongly. You divide the Euclidean distance instead of just difference in the X-coordinate.
Logic for the y is flawed. At least you should add m * (x - x1) instead of m * x. But it still won't cover the case of a vertical shoot (i.e. the case when the X-coordinate is not changed at all). If you want to go this way, you should use xPerF and yPerF and get rid of the m and the related if's.
This might or might not fix the animation issues (at list you still will have a potential for rounding errors). I'd still say that changing your shoot to something like
public void shootTarget(int target) {
shotTarget = target;
shotTime = animationFrame;
}
and then using
double animationPart = ((double) (animationFrame - shotTime)) / animationSpeed;
as suggested above is a better way. Note: this is only a stub because in your real code you for some reason regularly assign 0 to refresh and thus to animationFrame so it won't work that easy.
Answer
I figured it out. Instead of calculating the coordinates with slope-intercept method, I simply calculated the intervals I would have to increment y and x per frame and incremented them based on the frame of the animation.
double x, y, xPerF, yPerF; //Values for drawing
double x1, x2, y1, y2; //Values for the targets
x1 = getCenterX();
x2 = Canvas.target[shotTarget].getCenterX();
y1 = getCenterY();
y2 = Canvas.target[shotTarget].getCenterY();
xPerF = (Math.max(x1, x2) - Math.min(x1, x2))/animationSpeed;
yPerF = (Math.max(y1, y2) - Math.min(y1, y2))/animationSpeed;
if(x1>x2) x = x1 - xPerF * animationFrame;
else if(x1<x2) x = x1 + xPerF * animationFrame;
else x = x1;
if(y1>y2) y = y1 - yPerF * animationFrame;
else if(y1<y2) y = y1 + yPerF * animationFrame;
else y = y1;
g.fillOval((int) x - 15, (int) y - 15, 30, 30);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have solved this problem but im not sure if its correct..
User should give the coordinates of a point and I should check if that point is within,outside or on the circle. I used the distance formula to solve this .
The given information about the circle are:
Circle is centered at ( 0,0 )
and radius is 10
public static void main(String[] strings) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter a point with two coordinates");
double y1 = scanner.nextDouble();
double x1 = scanner.nextDouble();
// circle is centered at 0,0
double y2 = 0;
double x2 = 0;
double radius = 10;
double distance;
// using the distance formula to calculate the distance
// from the point given from the user and point where circle is centered
/**
* distance formula
* d = √ ( x2 - x1 )^2 + (y2 - y1 )^2
*/
distance = Math.pow( x2 - x1,2) + Math.pow(y2-y1,2);
// find square root
distance = Math.sqrt(distance);
String result="";
if(distance < radius) {
result = "("+y1+" , "+x1+")" +" is within the circle";
}
else if(distance > radius) {
result = y1+" , "+x1 +" is outside the circle";
}
else if(distance == radius) {
result =y1+" , "+x1 +" is on the circle";
}
System.out.println(result);
}
It's fine but sloppy.
There's no need to compute the square root. Work in units of distance squared.
Then compare using distance < radius * radius etc., perhaps renaming distance for the sake of clarity. Computing square roots is costly and imprecision can creep in which can be difficult to control. This is particularly important in your case where you want to test for a point being on the circle's edge.
Also consider writing (x2 - x1) * (x2 - x1) rather than using pow for the second power. Although Java possibly (I never remember for sure which is certainly a good enough reason for my not using it) optimises to the longer form, other languages (such as C) don't and imprecision can creep in there too.
Are you sure this question requires doubles as input? The examples given are integers. With integers you can be sure of a points location, with real numbers (doubles) you cannot be sure about the "on circle" or not which is another reason I think the question expects you to use integers.
And the trick for performance and accuracy is to not use Math.sqrt and only work with integers.
int x;
int y;
int centreX;
int centreY;
int deltaX = x - centreX;
int deltaY = y - centreY;
int distanceSquared = deltaX * deltaX + deltaY * deltaY;
int radiusSquared = radius * radius;
if (distanceSquared == radiusSquared) { //distance == radius
//on circle
} else if (distanceSquared < radiusSquared) { //distance < radius
//in circle
} else {
//out of circle
}
Consider using Math.hypot() to calculate a distance and compare double values using some small threshold:
static final double DELTA = 1E-5; // not necessarily 1E-5; see comments
//...
distance = Math.hypot(x2 - x1, y2 - y1);
if (Math.abs(distance - radius) < DELTA)
// on the circle
else if (distance > radius)
// outside
else
// inside
The reason for using DELTA is that there is a very small chance to get equal double values by calculations. If they differ in at least one bit, direct comparison will return false.
By appliying threshold, you check not whether the point lays exactly on the circle, but whether it lays inside a ring between radius - DELTA and radius + DELTA. So DELTA is a kind of tolerance limit which value should be chosen particularily for application, e. g. depending on absolute or relative input inaccuracy.
I have drawn a line between two points A(x,y)---B(x,y)
Now I have a third point C(x,y). I want to know that if C lies on the line which is drawn between A and B.
I want to do it in java language. I have found couple of answers similar to this. But, all have some problems and no one is perfect.
if (distance(A, C) + distance(B, C) == distance(A, B))
return true; // C is on the line.
return false; // C is not on the line.
or just:
return distance(A, C) + distance(B, C) == distance(A, B);
The way this works is rather simple. If C lies on the AB line, you'll get the following scenario:
A-C------B
and, regardless of where it lies on that line, dist(AC) + dist(CB) == dist(AB). For any other case, you have a triangle of some description and 'dist(AC) + dist(CB) > dist(AB)':
A-----B
\ /
\ /
C
In fact, this even works if C lies on the extrapolated line:
C---A-------B
provided that the distances are kept unsigned. The distance dist(AB) can be calculated as:
___________________________
/ 2 2
V (A.x - B.x) + (A.y - B.y)
Keep in mind the inherent limitations (limited precision) of floating point operations. It's possible that you may need to opt for a "close enough" test (say, less than one part per million error) to ensure correct functioning of the equality.
ATTENTION! Math-only!
You can try this formula. Put your A(x1, y1) and B(x2, y2) coordinates to formula, then you'll get something like
y = k*x + b; // k and b - numbers
Then, any point which will satisfy this equation, will lie on your line.
To check that C(x, y) is between A(x1, y1) and B(x2, y2), check this: (x1<x<x2 && y1<y<y2) || (x1>x>x2 && y1>y>y2).
Example
A(2,3) B(6,5)
The equation of line:
(y - 3)/(5 - 3) = (x - 2)/(6 - 2)
(y - 3)/2 = (x - 2)/4
4*(y - 3) = 2*(x - 2)
4y - 12 = 2x - 4
4y = 2x + 8
y = 1/2 * x + 2; // equation of line. k = 1/2, b = 2;
Let's check if C(4,4) lies on this line.
2<4<6 & 3<4<5 // C between A and B
Now put C coordinates to equation:
4 = 1/2 * 4 + 2
4 = 2 + 2 // equal, C is on line AB
PS: as #paxdiablo wrote, you need to check if line is horizontal or vertical before calculating. Just check
y1 == y2 || x1 == x2
I believe the simplest is
// is BC inline with AC or visa-versa
public static boolean inLine(Point A, Point B, Point C) {
// if AC is vertical
if (A.x == C.x) return B.x == C.x;
// if AC is horizontal
if (A.y == C.y) return B.y == C.y;
// match the gradients
return (A.x - C.x)*(A.y - C.y) == (C.x - B.x)*(C.y - B.y);
}
You can calculate the gradient by taking the difference in the x values divided by the difference in the y values.
Note: there is a different test to see if C appears on the line between A and B if you draw it on a screen. Maths assumes that A, B, C are infinitely small points. Actually very small to within representation error.
The above answers are unnecessarily complicated. The simplest is as follows.
if (x-x1)/(x2-x1) = (y-y1)/(y2-y1) = alpha (a constant), then the point C(x,y) will lie on the line between pts 1 & 2.
If alpha < 0.0, then C is exterior to point 1.
If alpha > 1.0, then C is exterior to point 2.
Finally if alpha = [0,1.0], then C is interior to 1 & 2.
Hope this answer helps.
I think all the methods here have a pitfall, in that they are not dealing with rounding errors as rigorously as they could. Basically the methods described will tell you if your point is close enough to the line using some straightforward algorithm and that it will be more or less precise.
Why precision is important? Because it's the very problem presented by op. For a computer program there is no such thing as a point on a line, there is only point within an epsilon of a line and what that epsilon is needs to be documented.
Let's illustrate the problem. Using the distance comparison algorithm:
Let's say a segment goes from (0, 0) to (0, 2000), we are using floats in our application (which have around 7 decimal places of precision) and we test whether a point on (1E-6, 1000) is on the line or not.
The distance from either end of the segment to the point is 1000.0000000005 or 1000 + 5E-10, and, thus, the difference with the addition of the distance to and from the point is around 1E-9. But none of those values can be stored on a float with enough precission and the method will return true.
If we use a more precise method like calculating the distance to the closest point in the line, it returns a value that a float has enough precision to store and we could return false depending on the acceptable epsilon.
I used floats in the example but the same applies to any floating point type such as double.
One solution is to use BigDecimal and whichever method you want if incurring in performance and memory hit is not an issue.
A more precise method than comparing distances for floating points, and, more importantly, consistently precise, although at a higher computational cost, is calculating the distance to the closest point in the line.
Shortest distance between a point and a line segment
It looks like I'm splitting hairs but I had to deal with this problem before. It's an issue when chaining geometric operations. If you don't control what kind of precission loss you are dealing with, eventually you will run into difficult bugs that will force you to reason rigorously about the code in order to fix them.
An easy way to do that I believe would be the check the angle formed by the 3 points.
If the angle ACB is 180 degrees (or close to it,depending on how accurate you want to be) then the point C is between A and B.
I think this might help
How to check if a point lies on a line between 2 other points
That solution uses only integers given you only provide integers which removes some pitfalls as well
Here is my C# solution. I believe the Java equivalent will be almost identical.
Notes:
Method will only return true if the point is within the bounds of the line (it does not assume an infinite line).
It will handle vertical or horizontal lines.
It calculates the distance of the point being checked from the line so allows a tolerance to be passed to the method.
/// <summary>
/// Check if Point C is on the line AB
/// </summary>
public static bool IsOnLine(Point A, Point B, Point C, double tolerance)
{
double minX = Math.Min(A.X, B.X) - tolerance;
double maxX = Math.Max(A.X, B.X) + tolerance;
double minY = Math.Min(A.Y, B.Y) - tolerance;
double maxY = Math.Max(A.Y, B.Y) + tolerance;
//Check C is within the bounds of the line
if (C.X >= maxX || C.X <= minX || C.Y <= minY || C.Y >= maxY)
{
return false;
}
// Check for when AB is vertical
if (A.X == B.X)
{
if (Math.Abs(A.X - C.X) >= tolerance)
{
return false;
}
return true;
}
// Check for when AB is horizontal
if (A.Y == B.Y)
{
if (Math.Abs(A.Y - C.Y) >= tolerance)
{
return false;
}
return true;
}
// Check istance of the point form the line
double distFromLine = Math.Abs(((B.X - A.X)*(A.Y - C.Y))-((A.X - C.X)*(B.Y - A.Y))) / Math.Sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y));
if (distFromLine >= tolerance)
{
return false;
}
else
{
return true;
}
}
def DistBetwPoints(p1, p2):
return math.sqrt( (p2[0] - p1[0])**2 + (p2[1] - p1[1])**2 )
# "Check if point C is between line endpoints A and B"
def PointBetwPoints(A, B, C):
dist_line_endp = DistBetwPoints(A,B)
if DistBetwPoints(A,C)>dist_line_endp: return 1
elif DistBetwPoints(B,C)>dist_line_endp: return 1
else: return 0
Here is a JavaScript function I made. You pass it three points (three objects with an x and y property). Points 1 and 2 define your line, and point 3 is the point you are testing.
You will receive an object back with some useful info:
on_projected_line - If pt3 lies anywhere on the line including outside the points.
on_line - If pt3 lies on the line and between or on pt1 and pt2.
x_between - If pt3 is between or on the x bounds.
y_between - If pt3 is between or on the y bounds.
between - If x_between and y_between are both true.
/**
* #description Check if pt3 is on line defined by pt1 and pt2.
* #param {Object} pt1 The first point defining the line.
* #param {float} pt1.x
* #param {float} pt1.y
* #param {Object} pt2 The second point defining the line.
* #param {float} pt2.x
* #param {float} pt2.y
* #param {Object} pt3 The point to test.
* #param {float} pt3.x
* #param {float} pt3.y
*/
function pointOnLine(pt1, pt2, pt3) {
const result = {
on_projected_line: true,
on_line: false,
between_both: false,
between_x: false,
between_y: false,
};
// Determine if on line interior or exterior
const x = (pt3.x - pt1.x) / (pt2.x - pt1.x);
const y = (pt3.y - pt1.y) / (pt2.y - pt1.y);
// Check if on line equation
result.on_projected_line = x === y;
// Check within x bounds
if (
(pt1.x <= pt3.x && pt3.x <= pt2.x) ||
(pt2.x <= pt3.x && pt3.x <= pt1.x)
) {
result.between_x = true;
}
// Check within y bounds
if (
(pt1.y <= pt3.y && pt3.y <= pt2.y) ||
(pt2.y <= pt3.y && pt3.y <= pt1.y)
) {
result.between_y = true;
}
result.between_both = result.between_x && result.between_y;
result.on_line = result.on_projected_line && result.between_both;
return result;
}
console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2}))
console.log("pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5})")
console.log(pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5}))
if ( (ymid - y1) * (x2-x1) == (xmid - x1) * (y2-y1) ) **is true, Z lies on line AB**
Start Point : A (x1, y1),
End Point : B (x2, y2),
Point That is on Line AB or Not : Z (xmid, ymid)
I just condensed everyone's answers and this formula works the best for me.
It avoids division by zero
No distance calculation required
Simple to implement
Edit: In case you are dealing with floats, which you most probably are,
use this:
if( (ymid - y1) * (x2-x1) - (xmid - x1) * (y2-y1) < DELTA )
where the tolerance DELTA is a value close to zero.
I usually set it to 0.05
I need to draw a smooth line through a set of vertices. The set of vertices is compiled by a user dragging their finger across a touch screen, the set tends to be fairly large and the distance between the vertices is fairly small. However, if I simply connect each vertex with a straight line, the result is very rough (not-smooth).
I found solutions to this which use spline interpolation (and/or other things I don't understand) to smooth the line by adding a bunch of additional vertices. These work nicely, but because the list of vertices is already fairly large, increasing it by 10x or so has significant performance implications.
It seems like the smoothing should be accomplishable by using Bezier curves without adding additional vertices.
Below is some code based on the solution here:
http://www.antigrain.com/research/bezier_interpolation/
It works well when the distance between the vertices is large, but doesn't work very well when the vertices are close together.
Any suggestions for a better way to draw a smooth curve through a large set of vertices, without adding additional vertices?
Vector<PointF> gesture;
protected void onDraw(Canvas canvas)
{
if(gesture.size() > 4 )
{
Path gesturePath = new Path();
gesturePath.moveTo(gesture.get(0).x, gesture.get(0).y);
gesturePath.lineTo(gesture.get(1).x, gesture.get(1).y);
for (int i = 2; i < gesture.size() - 1; i++)
{
float[] ctrl = getControlPoint(gesture.get(i), gesture.get(i - 1), gesture.get(i), gesture.get(i + 1));
gesturePath.cubicTo(ctrl[0], ctrl[1], ctrl[2], ctrl[3], gesture.get(i).x, gesture.get(i).y);
}
gesturePath.lineTo(gesture.get(gesture.size() - 1).x, gesture.get(gesture.size() - 1).y);
canvas.drawPath(gesturePath, mPaint);
}
}
}
private float[] getControlPoint(PointF p0, PointF p1, PointF p2, PointF p3)
{
float x0 = p0.x;
float x1 = p1.x;
float x2 = p2.x;
float x3 = p3.x;
float y0 = p0.y;
float y1 = p1.y;
float y2 = p2.y;
float y3 = p3.y;
double xc1 = (x0 + x1) / 2.0;
double yc1 = (y0 + y1) / 2.0;
double xc2 = (x1 + x2) / 2.0;
double yc2 = (y1 + y2) / 2.0;
double xc3 = (x2 + x3) / 2.0;
double yc3 = (y2 + y3) / 2.0;
double len1 = Math.sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
double len2 = Math.sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
double len3 = Math.sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
double k1 = len1 / (len1 + len2);
double k2 = len2 / (len2 + len3);
double xm1 = xc1 + (xc2 - xc1) * k1;
double ym1 = yc1 + (yc2 - yc1) * k1;
double xm2 = xc2 + (xc3 - xc2) * k2;
double ym2 = yc2 + (yc3 - yc2) * k2;
// Resulting control points. Here smooth_value is mentioned
// above coefficient K whose value should be in range [0...1].
double k = .1;
float ctrl1_x = (float) (xm1 + (xc2 - xm1) * k + x1 - xm1);
float ctrl1_y = (float) (ym1 + (yc2 - ym1) * k + y1 - ym1);
float ctrl2_x = (float) (xm2 + (xc2 - xm2) * k + x2 - xm2);
float ctrl2_y = (float) (ym2 + (yc2 - ym2) * k + y2 - ym2);
return new float[]{ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y};
}
Bezier Curves are not designed to go through the provided points! They are designed to shape a smooth curve influenced by the control points.
Further you don't want to have your smooth curve going through all data points!
Instead of interpolating you should consider filtering your data set:
Filtering
For that case you need a sequence of your data, as array of points, in the order the finger has drawn the gesture:
You should look in wiki for "sliding average".
You should use a small averaging window. (try 5 - 10 points). This works as follows: (look for wiki for a more detailed description)
I use here an average window of 10 points:
start by calculation of the average of points 0 - 9, and output the result as result point 0
then calculate the average of point 1 - 10 and output, result 1
And so on.
to calculate the average between N points:
avgX = (x0+ x1 .... xn) / N
avgY = (y0+ y1 .... yn) / N
Finally you connect the resulting points with lines.
If you still need to interpolate between missing points, you should then use piece - wise cubic splines.
One cubic spline goes through all 3 provided points.
You would need to calculate a series of them.
But first try the sliding average. This is very easy.
Nice question. Your (wrong) result is obvious, but you can try to apply it to a much smaller dataset, maybe by replacing groups of close points with an average point. The appropriate distance in this case to tell if two or more points belong to the same group may be expressed in time, not space, so you'll need to store the whole touch event (x, y and timestamp). I was thinking of this because I need a way to let users draw geometric primitives (rectangles, lines and simple curves) by touch
What is this for? Why do you need to be so accurate? I would assume you only need something around 4 vertices stored for every inch the user drags his finger. With that in mind:
Try using one vertex out of every X to actually draw between, with the middle vertex used for specifying the weighted point of the curve.
int interval = 10; //how many points to skip
gesture.moveTo(gesture.get(0).x, gesture.get(0).y);
for(int i =0; i +interval/2 < gesture.size(); i+=interval)
{
Gesture ngp = gesture.get(i+interval/2);
gesturePath.quadTo(ngp.x,ngp.y, gp.x,gp.y);
}
You'll need to adjust this to actually work but the idea is there.
I am creating a java application. I need to calculate the determinant of three point. I have calculated it:
static int determinant(Point point1, Point point2, Point point3) {
int x1 = point1.x;
int x2 = point2.x;
int x3 = point3.x;
int y1 = point1.y;
int y2 = point2.y;
int y3 = point3.y;
return (x1 * y2) + (x3 * y1) + (x2 * y3) - (x3 * y2) - (x2 * y1)
- (x1 * y3);
}
(I am not good in math)But, I found the following when I searched about it:
public int ccw(int p1, int p2, int p3)
{
return (xPoints[p2] - xPoints[p1])*(yPoints[p3] - yPoints[p1]) - (yPoints[p2] - yPoints[p1])*(xPoints[p3] - xPoints[p1]);
}
which one is the correct method? If the first method is the correct one, what does the second method do?
both equations are the same. there is no mathematical difference between the two.
someone better at math than I could probably give you the mathematic proof. I chose to go the practical route, implemented in python, because I can
def fun1(p1,p2,p3) :
print (p1[0]*p2[1])+(p3[0]*p1[1])+(p2[0]*p3[1]) - (p3[0]*p2[1]) - (p2[0]*
p1[1]) - (p1[0]*p3[1])
def fun2(p1,p2,p3) :
print (p2[0]-p1[0])*(p3[1]-p1[1])-(p2[1] - p1[1])*(p3[0]-p1[0])
>>> fun1((0,0),(9,1),(3,2))
15
>>> fun2((0,0),(9,1),(3,2))
15
>>> fun2((33,5),(4,6),(8,1))
141
>>> fun1((33,5),(4,6),(8,1))
141
for any 3 points, fun1 and fun2 will yield the same result.
The second version assumes that the points are defined in two one-dimensional arrays:
int [] xPoints;
int [] yPoints;
xPoints[p] holds the x position of point p
yPoints[p] holds the y position of point p
I haven't done the math, but perhaps the two methods actually calculate the same thing.