Drawing lines on Canvas - android

I am developing Mind mapping tool for android. I am creating this type of layout for my mind map http://www.examtime.com/files/2013/08/How-to-create-an-online-mind-map.jpg. Is there any way to create a these type of lines(as created in image) to connect objects at run time. Please Help

You should look into cubic bezier curves (splines). There is no easy way to do this simply with a Canvas. Here's an overview:
Bezier curves use 2 points (P0 - the origin & P1 - the destination), and 2 vectors (V0 - the direction the curve leaves P0, V1 - the direction the curve enters P1). For our purposes, P0, P1, V0, V1 should all be of the type PointF.
We will use t to denote the position on the path. When t = 0, the position is at P0, when t = 1, the position is at P1. Any value of t between 0 and 1 will be along the path. 0 <= t <= 1.
Now, just as an example, lets look at the curve that connects the "Nobody's perfect" node to the "Tidy up later" node.
In this case, P0 will be the right middle side of "Nobody's perfect", and P1 will be the bottom middle side of "Tidy up later".
We'll make both vectors perpendicular to the nodes they're leaving / entering, and so V0's value will be {P1.x - P0.x, 0}. This vector will point right, and will have the strength equivalent to the distance between the two nodes. In a similar manner, we'll construct the V1 vector pointing up towards the node: {0, P0.y - P1.y}
Now that you have the vectors and the points, you'll want to start drawing the curve. To do this, you'll iterate through t using some small stepping value that's dividable by 1, for example, 0.1, 0.025, 0.001, etc. Let's call this value "step" Each iteration will generate a point on the curve, and you'll want to connect a line between each of these points.
Here's a code sample for this part:
PointF start, end;
for (float t = 0; t < 1; t += step)
{
start = getBezierPosition(t);
end = getBezierPosition(t + step)
canvas.drawLine(start.x, start.y, end.x, end.y, paint);
}
Now, the hard part - calculating the position of the bezier curve at position t:
private PointF getBezierPosition(float t)
{
PointF result = new PointF();
float oneMinusT, x, y;
oneMinusT = 1 - t;
x = oneMinusT * oneMinusT * oneMinusT * P0.x +
3 * oneMinusT * oneMinusT * t * V0.x +
3 * oneMinusT * t * t * V1.x +
t * t * t * P1.x;
y = oneMinusT * oneMinusT * oneMinusT * P0.y +
3 * oneMinusT * oneMinusT * t * V0.y +
3 * oneMinusT * t * t * V1.y +
t * t * t * P1.y;
result.set(x, y);
return result;
}
This is the formula for a cubic bezier curve. You can learn more about it here.
I'll let you implement the logic of determining the locations of P0 & P1, and the directions of V0 & V1 (keep in mind that they should always be perpendicular to the node they're leaving / entering for best results). You'll need to play around with the logic to determine what side of the node the P is on, and it's most likely going to be linked to the logic you apply to positioning the nodes in the 1st place.
Also, for best results, try playing around with the stroke width of the paint you're drawing with. For example, When t = 0, use a stroke width of size 5, and when t = 1, use a stroke size of 3. Make sure to iterate smoothly between them (so if t = 0.5, the stroke width will be 4).
I'll admit, this stuff is a bit heavy on the mathematics, and might not be in the comfort zone of a beginner, but if you want to achieve dynamic curves like you showed in that picture, I'm afraid you're going to get your hands a bit dirty.
Best of luck man! Let me know how it all turned out :)

Related

Using trigonometry to shoot multiple bullets like a shotgun

I'm making a game where the player follows the mouse and a bullet gets shot out the players back end at the opposite direction that it is moving towards the mouse. Its a bit hard to explain in words so i quickly made a rough draft in paint.net to demonstrate.
Grey ball is the player. yellow cursor is where the player is touching on the touch screen. And the black balls are the bullets.
In example 1 and 2, the player is moving towards the cursor and bullets are behind shot in the opposite direction. What I want to o is like in example 3 where there is more than one bullet coming out the back and they are also spread out like a shotgun shot.
image:
http://i.stack.imgur.com/Q3Q18.png
My goal would be to allow the player to upgrade to be able to shoot more than one bullet at a time. All I want is for the player to be able to shoot up to 5 at a time. Thanks in advance!
The angles of the other bullets would use the same formula you are using, but the angles would be some constant offset relative to the center bullet. For instance, if you are using the following formula for the center bullet:
x += Math.cos(angle * Math.PI/180) * Status.bulletSpeed;
y += Math.sin(angle * Math.PI/180) * Status.bulletSpeed;
then your other bullets would be:
x1 += Math.cos((angle + 10) * Math.PI/180) * Status.bulletSpeed;
y1 += Math.sin((angle + 10) * Math.PI/180) * Status.bulletSpeed;
x2 += Math.cos((angle - 10) * Math.PI/180) * Status.bulletSpeed;
y2 += Math.sin((angle - 10) * Math.PI/180) * Status.bulletSpeed;
You can choose some other value other than 10 if you so choose. If you wanted to shoot 5 at a time, you would also use:
x3 += Math.cos((angle + 20) * Math.PI/180) * Status.bulletSpeed;
y3 += Math.sin((angle + 20) * Math.PI/180) * Status.bulletSpeed;
x4 += Math.cos((angle - 20) * Math.PI/180) * Status.bulletSpeed;
y4 += Math.sin((angle - 20) * Math.PI/180) * Status.bulletSpeed;
Here, the number you use should be twice the value you choose for the first set.

How to tell what part of a texture on a 3d cube was touched [duplicate]

I have a renderer using directx and openGL, and a 3d scene. The viewport and the window are of the same dimensions.
How do I implement picking given mouse coordinates x and y in a platform independent way?
If you can, do the picking on the CPU by calculating a ray from the eye through the mouse pointer and intersect it with your models.
If this isn't an option I would go with some type of ID rendering. Assign each object you want to pick a unique color, render the objects with these colors and finally read out the color from the framebuffer under the mouse pointer.
EDIT: If the question is how to construct the ray from the mouse coordinates you need the following: a projection matrix P and the camera transform C. If the coordinates of the mouse pointer is (x, y) and the size of the viewport is (width, height) one position in clip space along the ray is:
mouse_clip = [
float(x) * 2 / float(width) - 1,
1 - float(y) * 2 / float(height),
0,
1]
(Notice that I flipped the y-axis since often the origin of the mouse coordinates are in the upper left corner)
The following is also true:
mouse_clip = P * C * mouse_worldspace
Which gives:
mouse_worldspace = inverse(C) * inverse(P) * mouse_clip
We now have:
p = C.position(); //origin of camera in worldspace
n = normalize(mouse_worldspace - p); //unit vector from p through mouse pos in worldspace
Here's the viewing frustum:
First you need to determine where on the nearplane the mouse click happened:
rescale the window coordinates (0..640,0..480) to [-1,1], with (-1,-1) at the bottom-left corner and (1,1) at the top-right.
'undo' the projection by multiplying the scaled coordinates by what I call the 'unview' matrix: unview = (P * M).inverse() = M.inverse() * P.inverse(), where M is the ModelView matrix and P is the projection matrix.
Then determine where the camera is in worldspace, and draw a ray starting at the camera and passing through the point you found on the nearplane.
The camera is at M.inverse().col(4), i.e. the final column of the inverse ModelView matrix.
Final pseudocode:
normalised_x = 2 * mouse_x / win_width - 1
normalised_y = 1 - 2 * mouse_y / win_height
// note the y pos is inverted, so +y is at the top of the screen
unviewMat = (projectionMat * modelViewMat).inverse()
near_point = unviewMat * Vec(normalised_x, normalised_y, 0, 1)
camera_pos = ray_origin = modelViewMat.inverse().col(4)
ray_dir = near_point - camera_pos
Well, pretty simple, the theory behind this is always the same
1) Unproject two times your 2D coordinate onto the 3D space. (each API has its own function, but you can implement your own if you want). One at Min Z, one at Max Z.
2) With these two values calculate the vector that goes from Min Z and point to Max Z.
3) With the vector and a point calculate the ray that goes from Min Z to MaxZ
4) Now you have a ray, with this you can do a ray-triangle/ray-plane/ray-something intersection and get your result...
I have little DirectX experience, but I'm sure it's similar to OpenGL. What you want is the gluUnproject call.
Assuming you have a valid Z buffer you can query the contents of the Z buffer at a mouse position with:
// obtain the viewport, modelview matrix and projection matrix
// you may keep the viewport and projection matrices throughout the program if you don't change them
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
// obtain the Z position (not world coordinates but in range 0 - 1)
GLfloat z_cursor;
glReadPixels(x_cursor, y_cursor, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z_cursor);
// obtain the world coordinates
GLdouble x, y, z;
gluUnProject(x_cursor, y_cursor, z_cursor, modelview, projection, viewport, &x, &y, &z);
if you don't want to use glu you can also implement the gluUnProject you could also implement it yourself, it's functionality is relatively simple and is described at opengl.org
Ok, this topic is old but it was the best I found on the topic, and it helped me a bit, so I'll post here for those who are are following ;-)
This is the way I got it to work without having to compute the inverse of Projection matrix:
void Application::leftButtonPress(u32 x, u32 y){
GL::Viewport vp = GL::getViewport(); // just a call to glGet GL_VIEWPORT
vec3f p = vec3f::from(
((float)(vp.width - x) / (float)vp.width),
((float)y / (float)vp.height),
1.);
// alternatively vec3f p = vec3f::from(
// ((float)x / (float)vp.width),
// ((float)(vp.height - y) / (float)vp.height),
// 1.);
p *= vec3f::from(APP_FRUSTUM_WIDTH, APP_FRUSTUM_HEIGHT, 1.);
p += vec3f::from(APP_FRUSTUM_LEFT, APP_FRUSTUM_BOTTOM, 0.);
// now p elements are in (-1, 1)
vec3f near = p * vec3f::from(APP_FRUSTUM_NEAR);
vec3f far = p * vec3f::from(APP_FRUSTUM_FAR);
// ray in world coordinates
Ray ray = { _camera->getPos(), -(_camera->getBasis() * (far - near).normalize()) };
_ray->set(ray.origin, ray.dir, 10000.); // this is a debugging vertex array to see the Ray on screen
Node* node = _scene->collide(ray, Transform());
cout << "node is : " << node << endl;
}
This assumes a perspective projection, but the question never arises for the orthographic one in the first place.
I've got the same situation with ordinary ray picking, but something is wrong. I've performed the unproject operation the proper way, but it just doesn't work. I think, I've made some mistake, but can't figure out where. My matix multiplication , inverse and vector by matix multiplications all seen to work fine, I've tested them.
In my code I'm reacting on WM_LBUTTONDOWN. So lParam returns [Y][X] coordinates as 2 words in a dword. I extract them, then convert to normalized space, I've checked this part also works fine. When I click the lower left corner - I'm getting close values to -1 -1 and good values for all 3 other corners. I'm then using linepoins.vtx array for debug and It's not even close to reality.
unsigned int x_coord=lParam&0x0000ffff; //X RAW COORD
unsigned int y_coord=client_area.bottom-(lParam>>16); //Y RAW COORD
double xn=((double)x_coord/client_area.right)*2-1; //X [-1 +1]
double yn=1-((double)y_coord/client_area.bottom)*2;//Y [-1 +1]
_declspec(align(16))gl_vec4 pt_eye(xn,yn,0.0,1.0);
gl_mat4 view_matrix_inversed;
gl_mat4 projection_matrix_inversed;
cam.matrixProjection.inverse(&projection_matrix_inversed);
cam.matrixView.inverse(&view_matrix_inversed);
gl_mat4::vec4_multiply_by_matrix4(&pt_eye,&projection_matrix_inversed);
gl_mat4::vec4_multiply_by_matrix4(&pt_eye,&view_matrix_inversed);
line_points.vtx[line_points.count*4]=pt_eye.x-cam.pos.x;
line_points.vtx[line_points.count*4+1]=pt_eye.y-cam.pos.y;
line_points.vtx[line_points.count*4+2]=pt_eye.z-cam.pos.z;
line_points.vtx[line_points.count*4+3]=1.0;

Android : OpenGL 2.0 Rotation/moving the Camera using Matrix.setLookAtM

So this is my second question today, I might be pushing my luck
In short making a 3D first Person, where you can move about and look around.
In My OnDrawFrame I am using
Matrix.setLookAtM(mViewMatrix, 0, eyeX , eyeY, eyeZ , lookX , lookY , lookZ , upX, upY, upZ);
To move back, forth, sidestep left etc I use something like this(forward code listed)
float v[] = {mRenderer.lookX - mRenderer.eyeX,mRenderer.lookY - mRenderer.eyeY, mRenderer.lookZ - mRenderer.eyeZ};
mRenderer.eyeX += v[0] * SPEED_MOVE;
mRenderer.eyeZ += v[2] * SPEED_MOVE;
mRenderer.lookX += v[0] * SPEED_MOVE;
mRenderer.lookZ += v[2] * SPEED_MOVE;
This works
Now I want to look around and I tried to port my iPhone openGL 1.0 code. This is left/right
float v[] = {mRenderer.lookX - mRenderer.eyeX,mRenderer.lookY - mRenderer.eyeY, mRenderer.lookZ - mRenderer.eyeZ};
if (x > mPreviousX )
{
mRenderer.lookX += ((Math.cos(SPEED_TURN / 2) * v[0]) - (Math.sin(SPEED_TURN / 2) * v[2]));
mRenderer.lookZ += ((Math.sin(SPEED_TURN / 2) * v[0]) + (Math.cos(SPEED_TURN / 2) * v[2]));
}
else
{
mRenderer.lookX -= (Math.cos(SPEED_TURN / 2) *v[0] - Math.sin(SPEED_TURN / 2) * v[2]);
mRenderer.lookZ -= (Math.sin(SPEED_TURN / 2) *v[0] + Math.cos(SPEED_TURN / 2) * v[2]);
}
This works for like 35 degrees and then goes mental?
Any ideas?
First of all I would suggest not to trace the look vector but rather forward vector, then in lookAt method use eye+forward to generate look vector. This way you can loose the update on the look completely when moving, and you don't need to compute the v vector (mRenderer.eyeX += forward.x * SPEED_MOVE;...)
To make things more simple I suggest that you normalize the vectors forward and up whenever you change them (and I will consider as you did in following methods).
Now as for rotation there are 2 ways. Either use right and up vectors to move the forward (and up) which is great for small turning (I'd say about up to 10 degrees and is capped at 90 degrees) or compute the current angle, add any angle you want and recreate the vectors.
The first mentioned method on rotating is quite simple:
vector forward = forward
vector up = up
vector right = cross(forward, up) //this one might be the other way around as up, forward :)
//going left or right:
forward = normalized(forward + right*rotationSpeedX)
//going up or down:
forward = normalized(forward + up*rotationSpeedY)
vector right = cross(forward, up) //this one might be the other way around
vector up = normalized(cross(forward, right)) //this one might be the other way around
//tilt left or right:
up = normalized(up + right*rotationZ)
The second method needs a bit trigonometry:
Normally to compute an angle you could just call atan(forward.z/forward.x) and add some if statements since the produced result is only in 180 degrees angle (I am sure you will be able to find some answers on the web to get rotation from vector though). The same goes with up vector for getting the vertical rotation. Then after you get the angles you can easily just add some degrees to the angles and recreate the vectors with sin and cos. There is a catch though, if you rotate the camera in such way, that forward faces straight up(0,1,0) you need to get the first rotation from up vector and the second from forward vector but you can avoid all that if you cap the maximum vertical angle to something like +- 85 degrees (and there are many games that actually do that). The second thing is if you use this approach your environment must support +-infinitive or this atan(forward.z/forward.x) will brake if forward.x == 0.
And some addition about the first approach. Since I see you are trying to move around the 2D space your forward vector to use with movement speed should be normalized(forward.x, 0, forward.z), it is important to normalize it or you will be moving slower if camera tilts up or down more.
Second thing is when you rotate left/right you might want to force up vector to (0,1,0) + normalize right vector and lastly recreate the up vector from forward and right. Again you then should cap the vertical rotation (up.z should be larger then some small value like .01)
It turned out my rotation code was wrong
if (x > mPreviousX )
{
mRenderer.lookX = (float) (mRenderer.eyeX + ((Math.cos(SPEED_TURN / 2) * v[0]) - (Math.sin(SPEED_TURN / 2) * v[2])));
mRenderer.lookZ = (float) (mRenderer.eyeZ + ((Math.sin(SPEED_TURN / 2) * v[0]) + (Math.cos(SPEED_TURN / 2) * v[2])));
}
else
{
mRenderer.lookX = (float) (mRenderer.eyeX + ((Math.cos(-SPEED_TURN / 2) * v[0]) - (Math.sin(-SPEED_TURN / 2) * v[2])));
mRenderer.lookZ = (float) (mRenderer.eyeZ + ((Math.sin(-SPEED_TURN / 2) * v[0]) + (Math.cos(-SPEED_TURN / 2) * v[2])));
}

opengl android movement with given speed

This is a very basic issue, but I just can't find a complete answer anywhere.
Consider an object is moving along the z axis with a given SPEED. (Ex: -0.2 opengl units)
Now I rotate the object around its local axis with rotationX , Y and Z angles.
Question: what is the next position of my object?
I am using the following equations (which I know are wrong, but I just can't make them right)
positionX += -SPEED * Math.sin(rotationY * Utils.DEG)* Math.cos(rotationX * Utils.DEG);
positionY += SPEED * Math.sin(rotationX * Utils.DEG);
positionZ += -SPEED * Math.cos(rotationX * Utils.DEG)* Math.cos(rotationY * Utils.DEG);
Where is my mistake?
I would store a vector that represents the orientation of the object.
On rotation, rotate the orientation vector.
When moving,
positionX += SPEED * orientation.X
positionY += SPEED * orientation.Y
etc.

Android line drawing game (e.g. Flight Control) tutorial?

I'm looking for a tutorial that allows me to make a simple line tracing app, no other fancy stuff such as collision. If I can get an object to follow a line drawn on the screen at the end of this week that would be wonderful.
After getting familiar with android dev, creating a few apps (calculators, converters), I think I'm ready to step it up a bit with a game containing a main loop.
I think this is exactly what I'm looking for: http://www.rengelbert.com/tutorial.php?id=182
Here is the demo: http://www.rengelbert.com/swf/LineDrawing.html
Your question is actually quite vague and it would help if you actually supplied some code snippets, variables, formulas, to help us understand your scenario. I'm going to make the following assumptions to help me guide an answer:
I have a line segment defined by (x1, y1) - (x2, y2)
I want to make an animation of an object that follows the line segment
The object needs to be orientated the correct direction
Lets assume the object moves at a speed of 1 pixel per second
Okay, now we have established the parameters, we can provide some Java code:
// Define the line segment.
double x1 = /* ... insert value here */;
double y1 = /* ... insert value here */;;
double x2 = /* ... insert value here */;;
double y2 = /* ... insert value here */;;
// Determine both the direction and the length of the line segment.
double dx = x2 - x1;
double dy = y2 - y1;
double length = Math.sqrt(dx * dx + dy * dy); // length of the line segment
double orientation = Math.atan2(dy, dx);
// Now for any time 't' between 0 and length, let's calculate the object position.
double x = x1 + t * dx / length;
double y = y1 + t * dy / length;
showObjectAt(x, y, orientation);
As to following a tutorial on building a game loop for your application, I highly recommend you follow the series on http://www.mybringback.com/ particularly Travis' Android tutorial on working with the SurfaceView object at http://www.mybringback.com/tutorial-series/3266/android-the-basics-28-introduction-to-the-surfaceview/

Categories

Resources