I have a question about Android's "fingerpaint" example: https://github.com/Miserlou/Android-SDK-Samples/blob/master/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.java. There's a detail I can't seem to understand.
On an "ACTION_MOVE" motion event, the view draws a new path segment to the canvas using the Path.quadTo method. This happens on line 104. If I understand correctly, the current position of the Path is (mX, mY), and (x, y) is the location the user has moved the pointer to. So quadTo(mX, mY, (x + mX)/2, (y + mY)/2) should draw a quadratic bezier from (mX, mY), halfway to (x, y), using (mX, mY) as the control point.
I'm not an expert on beziers, but since the control point is collinear with the start and end points, this looks like it should just draw a straight line, meaning that we might as well have just called Path.lineTo instead. Moreover, when I run the app and move the pointer, a line is drawn all the way to the new location, not just halfway as I would have expected from the code. Replacing (x + mX)/2 and (y + mY)/2 with x and y , or replacing quadTo with lineTo, doesn't produce a perceptible difference in behavior.
Can anyone help resolve my confusion?
I've got the exact same question. After playing around a little with parameter values, what I understood is that:
Setting the control point coordinates to be the same as those of the starting point helps drawing a smoother curve.
Moreover, when I run the app and move the pointer, a line is drawn all the way to the new location, not just halfway as I would have expected from the code
What happens is that each time a new path is drawn, the distance between start and end points is calculated in pixels. For every slight move a new path is drawn. So, in the end we have lots of small paths drawn one after the other. You're correct that the path (line, curve) seems to be drawn all the way to the end and not just halfway. However, what actually happens is that it is indeed drawn halfway; the distance between each new path is so small that we don't notice that. Let me explain this with the screenshots below. In both cases, I tried to draw from one side of the screen to the other.
This is how it looks when using the coordinates given in the sample code
And this is how it looks if we use the end point coordinates as the actual end point coordinates in quadTo()
So, when we use the actual end point coordinates, the paths are more accurate in terms of where's the end point (notice how the end point to the right is more close to end of the screen in the 2nd photo?)
On the other side, the distance between start, control and end point plays part in the smoothness of the path. In the second screenshot, I used the halfway point as the control point and this resulted in less smooth paths.
At least that's what I have understood. If anyone has a more accurate explain, please share it.
Related
Could someone explain me how convex path is calculated? I need to draw some cubic and additionally some lines but then path is shown as non convex. However when I leave only lines or just cubic it is then convex. The problem is that I need some non regular shaped background and need Convex path for shadow outline but can't get how I could connect drawing cubic with some lines to make convex path if it is even possible
A path is convex if it has a single contour, and only ever curves in a single direction.
Convex means it keeps bending / rotating in one direction, and one direction only. You really have to make sure that all your angles and curves add up. If your curve connects to a line it has to have the same angle or be "more convex", I hope the following 2 images will clear this up.
The picture below is not convex. That's also likely your problem. The line connects to a curve, but the curve has a different angle than the line and it will change the direction where it connects. See where the line goes down but instead of continuing the downwards-motion it suddenly goes up again. Instead of keeping one direction it will change for a moment where line and curve meet.
The above Image is exaggerated for clarity, but even small errors in the connection between the line and curve will trigger an error.
The next line connects to a curve with a steeper angle. This is convex and won't be a problem. See how the whole contour keeps a single motion in one direction, depending in which direction you follow it it keeps turning left/right.
I answered because I was facing a similar issue recently and I feel your pain. I recommend pen and paper to double and triple check the math and to use a small epsilon value to account for rounding errors etc... You really have to nail the math, because if your line and curve connection is just off by very little it will throw that exception.
Sorry for my bad paint skills
Okay, so I have two very simple separate Path objects, one containing a straight line I created with lineTo and one containing a curve that I generated with the quadTo function. I need to get the POINT (x, y) where these two objects insect, which they only do once as well as the DISTANCE from one side of the arc of the point where they intersect.
There are lots of posts about figuring out IF they intersect, but I can't find any information on how to figure out WHERE they intersect.
EDIT! I still can't figure this out, I've been trying to fake it by measuring the distance along the yellow line that the black lines were drawn apart from each other and then making a whole new curve. It's sloppy and not working well. See the image!
If I can get to the distance from the end where the black curve intersects the yellow line, I can get a segment of the curve, and the two points on it's end, and it will work great!
Any ideas, anyone? :)
Thanks!
We are creating an app where it is necessary to draw lines (curves) based on touch events but we also need to store the points that correspond to specific lines.
Android.Graphics.Path gave us really nice smooth lines as we dragged our finger. However, there does not seem to be anyway to access the points from the Path objects.
What we do now is basically connect lines as a person drags their finger (using y=mx+b). So if the last recognized touch place was 0,0 and then they move past our threshold to (4,4) we call a function to make points from the line connecting these two ((0,0),(1,1),(2,2),(3,3),(4,4)). These points we add to an ArrayList.
This is giving us kinda choppy curves (obviously cause we are using y=mx+b), but more importantly it slows our program considerably after several lines are drawn.
Is there a better way to generate the points of a curve that follows a user's swipe movements? Or a better way to store these? Path seems to do it so well, is there any reason it hides the actual points?
Thanks!
A way to achieve smoothness is using the Path class' method quadTo.
quadTo(float x1, float y1, float x2, float y2) Add a quadratic bezier
from the last point, approaching control point (x1,y1), and ending at
(x2,y2).
Bezier curves are what you want to solve this problem. You should be able to detect a change in direction of the user's finger and stop the current curve and start a new one at that point. You really don't want to be storing every point along a path as I could just let my finger linger on the screen and clog up the datastructure.
I am using FingerPaint example available in ApiDemos for drawing my finger movement on screen.
Now instead of line, I am adding circles in my path object and this path with circle will be drawn when onDraw method is called.
Now my issue is when I slowly move my finger it draws circles at the points given by onTouchEvent properly but when I move my finger with some speed, unlike line, it draws only few circles.
After debugging, I found that while moving finger rapidly, some of the touch events are dropped by the view and on that points circles are not drawn.
Can anyone give some pointers on this. Why this is happening?
Two things I can think of without seeing code.
First, are you getting the historical points recorded between touchEvents and using them also? If not, that would cause some serious jerkiness like you are talking about.
If you are, and it's just not picking them up, the best you'll be able to do might be to cheat it some. Check the distance between the current and last circle drawn. If it exceeds the circle's diameter too much, draw a line with the same thickness as the circle, with a circle on both ends.
Math has come on my way again and has defeated me. I need your help to regroup and attack again.
What I've got:
I've got a surfaceview and a circle as a bitmap. I need to rotate the bitmap as the user moves the finger around the circle edge. The faster the user slides, the more I need to rotate the image. Seems simple but not really easy to implement.
What I need
I need to calculate the angle on which to rotate the image on onDraw event. From what I've thought so far I need two things:
- the angle between new touched point and the old one. I've done a simple function that takes care of this:
private int getAngleBetweenTwoTouchedPoints(double oldX, double oldY, double newX, double newY)
{
return (int) Math.abs(Math.atan2(newY - oldY, newX - oldX));
}
the angle returned by this varies from 0 to 1 and I believe it is correct. By incrementing the image rotation matrix angle by this value I get a slow rotation, basically by 1 unit. So, there is a chance to work, but not ok yet.
- so, the second thing I may need is the speed with which the user slides the finger around the screen. So basically something like this:
rotationAngle += angleBetweenTouches+speed
Speed, or velocity as I saw it named is the problem in my case, considering that I don't move only on X or Y but around the circle. I have no idea how to calculate it. I saw VelocityTracker on Android help but I don't know how it could help.
So to recap: I need to be able to rotate the image as the user moves the finger around the image border. Even simpler, when the user stops sliding, the pixel of the image that was below the finger on slide start should be the same when the slide stops.
Any help is greatly appreciated. Thank you
I had the same task but for a different purpose with angles. i hope this link might give you some clue
http://www.andengine.org/forums/post9226.html#p9226
For time difference did you try getting getTime() from Date class between two different clicks?
Hope this give you some idea.
I suspect that given "Even simpler, when the user stops sliding, the pixel of the image that was below the finger on slide start should be the same when the slide stops. ", what you might be better off with is absolute rotations rather than relative ones.
Incrementing the rotation with each event may accumulate errors that lead to the bitmap not appearing to "stick" to the finger.
If you just keep track of the initial event and the last event, then always transform from the initial view to that appropriate for the last event your code will be simpler (avoiding speed), and behave better.