I'm testing the drawing of an XY graph on my Android tablet. It's a Samsung Galaxy Tab 2 (7") running ICS.
I've created a View subtype with an overridden onDraw method. Its job is to simply plot an array of (x,y) coordinates as a series of connected line segments. I've got a float array representing the y values, and the x values are the array indices. The y values extend from -1 to 1 and there are about 10 values. Pretty simple.
The target canvas is a square on the screen, say about 480 by 480 pixels, with +1 intended to be at the top of the screen and -1 at the bottom, and the 0th value at the extreme left and the Nth value at the extreme right.
Thus, the transformation from "world coordinates" to "screen coordinates" along the X and Y axes is not uniform. In my onDraw method, I apply a translate, a scale, and then another translate operation to the Canvas object, and then I proceed to draw the line segments using a Paint pen having a hairline stroke width of 0.
The result is a graph that's not hairline in width. Obviously, my scale operation is thickening the line segments so that gently sloping lines appear thicker than steep ones. When I change my world-coordinates extents so that they're equal along both axes (to match the square canvas), then this problem disappears.
Interestingly, this problem occurs on the tablet, but not on the Android ICS emulator.
Any thoughts on this would be appreciated. My preference is to have a hairline graph no matter what the transformation is.
The obvious work-around to this issue is to leave the canvas's matrix untouched and perform the translate/scale/translate operations myself (converting from world to screen coordinates), and then use the screen coordinates for drawing, utilizing a Paint pen with a width of 0.
Related
I am try to implement a hand-painted app by android (like infinite design )
and decide to use vector because it can scale and not distortion.
I think a lot and try to use the mode of viewport-horizon-world
Viewport which rely on the sizeof phone (etc 1080*1920) it is the path you see and you touch
Horizon the thing which will display on viewport
World the real coordinates of the point(which make up the path etc line
,bessel).
this model works like
first you touch the screen of phone and horizon will translate the point to the real world coordinates (if you move of scale) and save the value to world
second you can move and scale by gestures it will change the attribute of horizon etc you move left 100 and down 100 the horizon will know now it offset (100,100) and the bound will change ((0,0),(1080,1920))->((100,100),(1180,2020))
last when draw i find the path which include in horizon (calculate the bound of horizon and the bound of path) then calculate the display coordinate rely on horizonand draw the path by canvas.draw() etc
now the problem is when i just offset the horizon ,calculate the display coordinate just need to plus the offset values.but when scale it become difficult.for example a path bound in ((0,0),(100,100)) and the horizon scale 0.5 in point (500,500) i don't know the position of the bound and don't know how to calculate the anchor of new path the size and width(maybe just multiplied by the scale factor)
the function i want to implement like the viewport in svg
i think it should use coordinate mapping but how?
please give me some clue
I would like to detect collisions between shapes dynamically drawn on a canvas (SurfaceView) for an Android game.
I can easily use intersect method of Rect or RectF objects but the result is not very good (see picture below where I have a "false" detection).
I don't want to use Bitmap so it's impossible to use the "pixel perfect" method.
Do you know a way to do this for circle, rect, triangle and other basic shapes intersection ?
Thx for help ;)
For a good collision detection you have to create your own models behind. In those models you specify the conditions that two objects colide.
For example, a circle is described by the center position and by the radius. A square is described by the left down corner and by the edge length.
You don' t have to describe all possible poligons, you can use the so called bounding boxes, meaning that, for a complex random poligon you can use a square or whathever shape fits it best(also you can use multiple shapes for a single object).
After you have the objects in mind you compute the condition that each one of them will colide with all other shapes including itself.
In your example The sphere and the square colides if the distance between any corner of the square is greater than the circle's radius.
Here you can read more http://devmag.org.za/2009/04/13/basic-collision-detection-in-2d-part-1/
This problem can get very complex, keep it simple if you want something simple.
Here is a directly applicable method I use in my own game to detect circle and rectangle intersection. It takes the ball (which is a view in this case) and the rectangle (also a view) to be checked for collision with the ball as parameters. You can put the method in a Timer and set the interval you want the circle and rectangle to be checked for collision.
Here is the method:
public boolean intersects(BallView ball, Rectangle rect) {
boolean intersects = false;
if (ball.getX() + ball.getR() >= rect.getTheLeft() &&
ball.getX() - ball.getR() <= rect.getTheRight() &&
ball.getY() + ball.getR() <= rect.getTheBottom() &&
ball.getY() - ball.getR() >= rect.getTheTop())
{
intersects = true;
}
return intersects;
}
getR() gets the circle's radius
getX() gets the center of the circle's X position value
getTheLeft() gets the rectangle's left X value
getTheRight() gets the rectangle's right X value
getTheTop() gets the rectangle's top Y value
getTheBottom() gets the rectangle's bottom Y value
If you can't directly use this method in your code you can still conjecture the logic it entails to implement it where it would work for you. It detects all collisions without using pseudo-collision detection like a collision box for the circle.
Good luck! And if you have any questions feel free to ask, I'm here to help!
To know if a polygon in 2d is colliding with a circle, you can test, for each of its lines, where is the point on the line that is closest to the center of the circle (this might help).
Then, check if the point you found is between to two corners that make the line - that is, that the point is actually on the line, and not just on its continuation - and if the distance of that point to the center of the circle is smaller or equal to the radius of the circle. If both are true for any of the lines of the polygon, you have a collusion. You also have to check for the edge cases where the corners of the polygon might be in, or touching the circle.
For two circles, this is easier. Check the distance between the centers, and compare it to the sum of their radiuses. If the distance is smaller or equal to the sum, you have a collusion.
I'm using OpenGL ES 2.0 on Android and I and I initialise my display like so:
float ratio = (float) width / height;
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); //Using Orthographic as developing 2d
What I'm having trouble understanding is this:
Let's say my app is a 'fixed screen' game (like Pac-Man ie, no scrolling, just the whole game visible on the screen).
Now at the moment, if I draw a quad at -1 to +1 on both x and y I get something like this:
Obviously, this is because I am setting -ratio, ratio as seen above. So this is correct.
But am I supposed to use this as my 'whole' screen? With rather massive letterboxing on the left and right?
I want a rectangular display that is the whole height of the physical display (and as much of the width as possible), but this would mean drawing at less that -1 and more than +1, is this a problem?
I realise the option may be to use clipping if this was a scrolling game, but for this particular scenario I want the whole 'game board' on the screen and to be static (And to use as much of the available screen real estate as possible without 'stretching' thus causing elongation of my sprites).
As I like to work with 0,0 as the top of the screen, basically what I do is pass my draw method something like so:
quad1.drawQuad (10,0);
When the drawQuad method get's this, it basically takes the range from left to right as expressed my openGL and divide the the screen width (so, in my case -1.7 through +1.7 so 3.4/2560 = 0.001328125). And say I specify 10 as my X (as above), it will say something like:
-1.7 + (10*0.001328125) = -1.68671875
It then plots the quad at -1.68671875.
Doing this I am able to work with normal co-ords (and I just subtract rather than add for y axis so I can have 0 at the top).
Is this a good way to do things?
Because with this method, at the moment, if I specify a 100,100 square, it isn't a square, it's rectangle. However, on the plus side, I can fill the whole physical screen by scaling the quad by width x height.
You are drawing a 1x1 quad, so that is why you see a 1x1 quad. Try translating the quad 0.25 to the right or left and you will see that you can draw in that space too.
In graphics, you create an object, like a quad, in your case you made it 1x1. Then you position it wherever you want. If you do not position it, then it will be at the origin, which is what you see.
If you draw a wider shape, you will also see you can draw outside this area on the screen.
By the way, with your ortho matrix function, you aren't just specifying the screen aspect ratio, you are also specifying the coordinate unit size you have to work with. This is why a 1x1 is filling the height the of the screen, because your upper and lower boundaries are set to 1 and -1. Your ratio is a little more than one, since your width is longer than your height, so your left and right boundaries are essentially something like -1.5 and 1.5 (whatever your ratio happens to be).
But you can also do something like this;
Matrix.orthoM(mProjMatrix, 0, -width/2, width/2, -height/2, height/2, 3, 7);
Here, your ratio is the same, but you are sending it to your ortho projection with screen coordinates. (Disclaimer: I don't use the same math library you do, but these appears to be a conventional ortho matrix function based on the arguments you are passing to it).
So lets say you have a 1000x500 pixel resolution. In OpenGL your origin of 0,0 is in the middle. So now your left edge is at (-500,y), right edge at (500,y) and your top is (x,250). So if you draw your 1x1 quad, it will be very tiny, but if you draw a 250x250 square, it will look like your 1x1 quad in your previous ortho projection.
So you can specify the coordinates you want, the ratio, the unit size, etc for how you want to work. Personally, I dont't like specifying coordinates as fractions between 0 and 1, I like to think about them in the same sense as the screen pixels.
But whether or not you choose to do this, hopefully you understand what you are actually passing to these matrix functions.
One of the best ways to learn is draw an object to the screen and just play around with different numbers you send to your modelview and projection matrices so you can see what it is they are actually doing.
I am currently creating an android game and implemented collision detection a while back. I am simply drawing a Rect around sprites using their position, width and height and seeing if they intersect other Rects. However, my sprites now rotate depending on their trajectory, but I cannot find how to rotate the Rect so the bound is correct. Any suggestions?
Thanks
Andy
Rect objects are usually axis-aligned, and so they only need 4 values: top, left, bottom, right.
If you want to rotate your rectangle, you'll need to convert it to eight values representing the co-ordinate of each vertex.
You can easily calculate the centre value by averaging all the x- and y-values.
Then it's just basic maths. Here's something from StackOverflow:
Rotating a point about another point (2D)
Your eight values, or four corners are (assuming counter-clockwise from the top right):
v0 : (right, top)
v1 : (left, top)
v2 : (left, bottom)
v3 : (right, bottom)
Create your own rectangle object to cope with this, and compute intersections etc.
Note that I've talked about how to rotate the rectangle's vertices. If you still want a bounding box, this is normally still considered to be axis-aligned, so you could take the max and min of the rotated vertices and construct a new (larger) rectangle. That might not be what you want though.
I am trying to learn opengl stuff on Android. In the gl.gltranslatef(x,y,z) call, I am shifting my texture by some units in the +ve x direction. But I am unable to find the number of pixels does 1 unit of x belong to?
Here is what I am doing:
I call gl.glviewport(0,0,width,height); // This will set my rectangle with 0,0 as lowerleft corner and then extend it to accommodate width and height.
Then
I call to gl.glfrustrum(-5,5,-7,7,3,7); // I am little confused how this call is using the dimensions I set in gl.glviewport.
How will -5 to 5 units from left to right in the above call, translate to pixels on the screen of android?
I mean if width = 320 and height = 533 pixels, then what will be the number of pixels occupied on the screen due to the gl.glfrustrum call?
I am experimenting in the gl.gltranslatef call by specifying xshift as 5.0, but it does not translate the bitmap at the right or left corner of the screen, when I increase it to 6, part of it is still visible on the screen.
Thanks
Siddhesh
In short, I am searching for the maximum number of units (in terms of X) which will represent extreme corners of my android phone screen.
glViewpoint tells it what rectangle (in pixels) your OpenGL output should be displayed in.
glFrustum tells it what coordinates in your "world" units should be mapped to that viewport.
An important point: your glFrustum call includes not only a height and width, but also a depth. Since you are specifying a Frustum, not a cube, that means anything with a Z coordinate anywhere but the very front of your frustum will be scaled down appropriately for its distance from the viewer.
As such, when you to a glTranslatef, the distance by which a particular object will move (in terms of pixels) will depend on its distance from the viewer. The further away it is from the viewer, the fewer pixels a particular sideways or up/down will translate to.
Depending on what else you're doing, one easy way to deal with this might be to use glOrtho instead of glFrustum. glOrtho gives orthographic mode, which means no perspective scaling is done, so a given X or Y distance will translate to the same number of pixels, regardless of distance from the viewer.