How can i draw a cylinder in OpenGL-es on Android? - android

Can any one help me to draw a cylinder in OpenGL-es android. Whatever i draw its look like a rectangle.
I would appreciate any tips or link.
Here is the code i've tried:
int VERTICES=180; // more than needed
float coords[] = new float[VERTICES * 3];
float theta = 0;
for (int i = 0; i < VERTICES * 3; i += 3) {
coords[i + 0] = (float) Math.cos(theta);
coords[i + 1] = (float) Math.sin(theta);
coords[i + 2] = 0;
_vertexBuffer.put(coords[i + 0]);
_vertexBuffer.put(coords[i + 1]);
_vertexBuffer.put(coords[i + 2]);
theta += Math.PI / 90;
}

This will only draw a circle. A cylinder is more complicated as you will need to define vertices in a translated z plane. And define them with correct normals (either facing in as if you were inside the cylinder -ie a tunnel or out as in looking at a pipe) which is the trickier part.
I'm currently doing this now (which is what brought me here) and have the cylinder drawn but pretty sure my normals are incorrect as my lighting looks a bit off. I'll post some code when I figure it out.
Edit : realized the code also doesn't actually draw a circle. Here is how to do that (in 2D) :
R = Radius
NUM_VERTICES = Number of vertices you want to use in circle
delta = (Math.PI / 180) * (360 / NUM_VERTICES); //get delta in radians between vertex definition
for i = 0 ; i < NUM_VERTICES ; i ++
x = R * cos(Delta * i)
y = R * sin(Delta * i))
vertices[i] = x; vertices[i+1] = y; vertices[i+2] = 0;
end for
//note may need to redefine the original vertex to complete the circle depending on which GL draw type you are using. If so just take the arg to sin / cos to be 0 to complete the loop
Last Edit* : just realized I was overcomplicating the normals by re-using some calculate normal from triangle code I had. Instead I realized how simple the normal calculation is for a cylinder if you consider the the origin 0,0 to be the center of each circular strip. The normal will be = vertex position scaled to length 1. for normals facing in on a cylinder (ie tunnel) the x,y values would be inverted (this is a assuming you are looking down the -z axis).

Related

opengl object vibrate after moving a distance

I have an object which moves on a terrain and a third person camera follow it, after I move it for some distance in different directions it begin to shaking or vibrating even if it is not moving and the camera rotates around it, this is the moving code of the object
double& delta = engine.getDeltaTime();
GLfloat velocity = delta * movementSpeed;
glm::vec3 t(glm::vec3(0, 0, 1) * (velocity * 3.0f));
//translate the objet atri before rendering
matrix = glm::translate(matrix, t);
//get the forward vetor of the matrix
glm::vec3 f(matrix[2][0], matrix[2][1], matrix[2][2]);
f = glm::normalize(f);
f = f * (velocity * 3.0f);
f = -f;
camera.translate(f);
and the camera rotation is
void Camera::rotate(GLfloat xoffset, GLfloat yoffset, glm::vec3& c, double& delta, GLboolean constrainpitch) {
xoffset *= (delta * this->rotSpeed);
yoffset *= (delta * this->rotSpeed);
pitch += yoffset;
yaw += xoffset;
if (constrainpitch) {
if (pitch >= maxPitch) {
pitch = maxPitch;
yoffset = 0;
}
if (pitch <= minPitch) {
pitch = minPitch;
yoffset = 0;
}
}
glm::quat Qx(glm::angleAxis(glm::radians(yoffset), glm::vec3(1.0f, 0.0f, 0.0f)));
glm::quat Qy(glm::angleAxis(glm::radians(xoffset), glm::vec3(0.0f, 1.0f, 0.0f)));
glm::mat4 rotX = glm::mat4_cast(Qx);
glm::mat4 rotY = glm::mat4_cast(Qy);
view = glm::translate(view, c);
view = rotX * view;
view = view * rotY;
view = glm::translate(view, -c);
}
float is sometimes not enough.
I use double precision matrices on CPU side to avoid such problems. But as you are on Android it might not be possible. For GPU use floats again as there are no 64bit interpolators yet.
Big numbers are usually the problem
If your world is big then you are passing big numbers into the equations multiplying any errors and only at the final stage the stuff is translated relative to camera position meaning the errors stay multiplied but the numbers got clamped so error/data ratio got big.
To lower this problem before rendering convert all vertexes to coordinate system with origin at or near your camera. You can ignore rotations just offset the positions.
This way you will got higher errors only far away from camera which is with perspective not visible anyway... For more info see:
ray and ellipsoid intersection accuracy improvement
Use cumulative transform matrix instead of Euler angles
for more info see Understanding 4x4 homogenous transform matrices and all the links at bottom of that answer.
This sounds like a numerical effect to me. Even small offsets coming from your game object will influence the rotation of the following camera with small movements / rotations and it looks like a vibrating object / camera.
So what you can do is:
Check if the movement above a threshold value before calculating a new rotation for your camera
When you are above this threshold: do a linear interpolation between the old and the new rotation using the lerp-algorithm for the quaternion ( see this unity answer to get a better understanding how your code can look like: Unity lerp discussion )

How to draw watchface 'ticks' on a square watch?

I currently have this snippet generating the ticks around the outside of and android wear watchface
float innerMainTickRadius = mCenterX - 35;
for(int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
float innerX = (float) Math.sin(tickRot) * innerMainTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerMainTickRadius;
float outerX = (float) Math.sin(tickRot) * mCenterX;
float outerY = (float) -Math.cos(tickRot) * mCenterX;
canvas.drawLine(mCenterX + innerX, mCenterY + innerY, mCenterX + outerX, mCenterY + outerY, mTickPaint);
}
Which generates the ticks well on a round watchface but on a square it turns out like this:
but I'd like them to not be circular, but instead fit the shape a bit more suitably, e.g:
Is there a standard way to do this? I'm guessing I can't use trig again...
Of course you use geometry and trig. For example any line you put on the clock face you want to point to the center so one part will be the given (x,y) and the other will be arctan2(cy-y,cx-x) giving you the angle from the point you have towards the center (cx,cy) then simply draw the line in the direction of the center of a given length r, by drawing the line from x,y to cos(angle) * r, sin(angle) * r.
However, given your sample image you might want to draw the line from x,y to x+r,y then rotate the canvas by angle so that you can draw those numbers tweaked like that. Be sure to do canvas.save() before tweaking the canvas' matrix and canvas.restore() after the tweak.
This leaves the math of whatever shape you want to draw your ticks from and the positions thereto. You can do this within a Path. So define the path for a rounded rectangle and then use the PathMeasure class to get the getPosTan() and then ignore the tangent and just use the position it gives you to find your position around a rounded rectangle. That or simply calculate those positions as the positions through either a line segment or a bezier section depending on the decided shape.
For example:
static final int TICKS = 12;
static final float TICKLENGTH = 20;
In the draw routine,
float left = cx - 50;
float top = cy - 50;
float right = cx + 50;
float bottom = cy + 50;
float ry = 20;
float rx = 20;
float width = right-left;
float height = bottom-top;
Path path = new Path();
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);
path.rLineTo(-(width - (2 * rx)), 0);
path.rQuadTo(-rx, 0, -rx, ry);
path.rLineTo(0, (height - (2 * ry)));
path.rQuadTo(0, ry, rx, ry);
path.rLineTo((width - (2 * rx)), 0);
path.rQuadTo(rx, 0, rx, -ry);
path.rLineTo(0, -(height - (2 * ry)));
path.close();
PathMeasure pathMeasure = new PathMeasure();
pathMeasure.setPath(path,true);
float length = pathMeasure.getLength();
float[] pos = new float[2];
float r = TICKLENGTH;
for (int i = 0; i < TICKS; i++) {
pathMeasure.getPosTan(i * (length/TICKS),pos,null);
double angle = Math.atan2(cy - pos[1], cx - pos[0]); //yes, y then x.
double cos = Math.cos(angle);
double sin = Math.sin(angle);
canvas.drawLine(pos[0], pos[1], (float)(pos[0] + cos * r), (float)(pos[1] + sin * r), paint);
}
Admittedly it looks like:
So it would take a lot more work to get it looking like your image. But, it's totally doable. The path measure trick thing will work for any shape. I avoided using path.addRoundRect because of the Lollipop+ restriction. You can see my answer to that question here. And the other answers which are plenty fine to how to draw a rounded rectangle-esque shape. You can, if you would like to write an envelope function simply scale your current picture to the envelope of the rectangle according to the factor t, as it goes around the clock.
The angle is a function of the position now. I'm not immediately seeing the trick for getting a closed form in this case. But in the most general case, you could end up just storing the position of each tickmark, then you're just drawing the line that goes through that point and the center. so the angle at second i is just
theta(i)=arctan(y_pos(i) / x_pos(i))
assuming the center has coordinates (0,0). In this case, you only need to store the positions for 8 consecutive ticks because the face is periodic every 90 degrees and symmetric about the diagonals as well.

Best way to draw a path traveled

I'm making a application to track a veicle based in GPS coordinates.
I created a SurfaceView to draw the field, vehicle and the path (route) for him.
The result looked like this:
The black dots represent the coming of GPS coordinates, and blue rectangles would be the area covered by the path traveled. (the width of the path is configurable)
The way I'm drawing with blue rectangles (this is my question) which are the area covered by the path traveled. (the width of the path is configurable)
With that I need to overcome some situation.
I need to calculate the field's rotation angle so that the path always get left behind. (completed)
I need to calculate the angle of rotation of each rectangle so they are facing towards the vehicle. (completed)
In the future I will need:
Detect when the vehicle passes twice in the same place. (based on the path traveled)
Calculate the area (m²) all traveled by the vehicle.
I would like some tips for draw this path.
My code:
public void draw(Canvas canvas) {
Log.d(getClass().getSimpleName(), "draw");
canvas.save();
// translate canvas to vehicle positon
canvas.translate((float) center.cartesian(0), (float) center.cartesian(1));
float fieldRotation = 0;
if (trackerHistory.size() > 1) {
/*
Before drawing the way, only takes the last position and finds the angle of rotation of the field.
*/
Vector lastPosition = new Vector(convertToTerrainCoordinates(lastPoint));
Vector preLastPosition = new Vector(convertToTerrainCoordinates(preLastPoint));
float shift = (float) lastPosition.distanceTo(preLastPosition);
/*
Having the last coordinate as a triangle, 'preLastCoord' saves the values of the legs, while 'shift' is the hypotenuse
*/
// If the Y offset is negative, then the opposite side is the Y displacement
if (preLastPosition.cartesian(1) < 0) {
// dividing the opposite side by hipetenusa, we have the sine of the angle that must be rotated.
double sin = preLastPosition.cartesian(1) / shift;
// when Y is negative, it is necessary to add or subtract 90 degrees depending on the value of X
// The "Math.asin()" calculates the radian arc to the sine previously calculated.
// And the "Math.toDegress()" converts degrees to radians from 0 to 360.
if (preLastPosition.cartesian(0) < 0) {
fieldRotation = (float) (Math.toDegrees(Math.asin(sin)) - 90d);
} else {
fieldRotation = (float) (Math.abs(Math.toDegrees(Math.asin(sin))) + 90d);
}
}
// if not, the opposite side is the X offset
else {
// dividing the opposite side by hipetenusa have the sine of the angle that must be rotated.
double senAngulo = preLastPosition.cartesian(0) / shift;
// The "Math.asin()" calculates the radian arc to the sine previously calculated.
// And the "Math.toDegress()" converts degrees to radians from 0 to 360.
fieldRotation = (float) Math.toDegrees(Math.asin(senAngulo));
}
}
final float dpiTrackerWidth = Navigator.meterToDpi(trackerWidth); // width of rect
final Path positionHistory = new Path(); // to draw the route
final Path circle = new Path(); // to draw the positions
/*
Iterate the historical positions and draw the path
*/
for (int i = 1; i < trackerHistory.size(); i++) {
Vector currentPosition = new Vector(convertToTerrainCoordinates(trackerHistory.get(i))); // vector with X and Y position
Vector lastPosition = new Vector(convertToTerrainCoordinates(trackerHistory.get(i - 1))); // vector with X and Y position
circle.addCircle((float) currentPosition.cartesian(0), (float) currentPosition.cartesian(1), 3, Path.Direction.CW);
circle.addCircle((float) lastPosition.cartesian(0), (float) lastPosition.cartesian(1), 3, Path.Direction.CW);
if (isInsideOfScreen(currentPosition.cartesian(0), currentPosition.cartesian(1)) ||
isInsideOfScreen(lastPosition.cartesian(0), lastPosition.cartesian(1))) {
/*
Calcule degree by triangle sides
*/
float shift = (float) currentPosition.distanceTo(lastPosition);
Vector dif = lastPosition.minus(currentPosition);
float sin = (float) (dif.cartesian(0) / shift);
float degress = (float) Math.toDegrees(Math.asin(sin));
/*
Create a Rect to draw displacement between two coordinates
*/
RectF rect = new RectF();
rect.left = (float) (currentPosition.cartesian(0) - (dpiTrackerWidth / 2));
rect.right = rect.left + dpiTrackerWidth;
rect.top = (float) currentPosition.cartesian(1);
rect.bottom = rect.top - shift;
Path p = new Path();
Matrix m = new Matrix();
p.addRect(rect, Path.Direction.CCW);
m.postRotate(-degress, (float) currentPosition.cartesian(0), (float) currentPosition.cartesian(1));
p.transform(m);
positionHistory.addPath(p);
}
}
// rotates the map to make the route down.
canvas.rotate(fieldRotation);
canvas.drawPath(positionHistory, paint);
canvas.drawPath(circle, paint2);
canvas.restore();
}
My goal is to have something like this application: https://play.google.com/store/apps/details?id=hu.zbertok.machineryguide (but only in 2D for now)
EDIT:
To clarify a bit more my doubts:
I do not have much experience about it. I would like a better way to draw the path. With rectangles it was not very good. Note that the curves are some empty spaces.
Another point is the rotation of rectangles, I'm rotating them at the time of drawing. I believe this will make it difficult to detect overlaps
I believe I need math help for the rotation of objects and overlapping detection. And it also helps to draw the path of a filled shape.
After some research time, I came to a successful outcome. I will comment on my thoughts and how was the solution.
As I explained in question, along the way I have the coordinates traveled by the vehicle, and also a setting for the width of the path should be drawn.
Using LibGDX library is ready a number of features, such as the implementation of a "orthographic camera" to work with positioning, rotation, etc.
With LibGDX I converted GPS coordinates on my side points to the road traveled. Like this:
The next challenge was to fill the path traveled. First I tried using rectangles, but the result was as shown in my question.
So the solution was to trace triangles using the side of the path as vertices. Like this:
Then simply fill in the triangles. Like this:
Finally, using Stencil, I set up OpenGL to highlight overlaps. Like this:
Other issues fixed:
To calculate the covered area, simply calculate the area of existing triangles along the path.
To detect overlapping, just check if the current position of the vehicle is within a triangle.
Thanks to:
AlexWien for the attention and for their time.
Conner Anderson by videos of LibGDX
And a special thanks to Luis Eduardo for knowledge, helped me a lot.
The sample source code.
Usually such a path is drawn using a "path" method from the graphics lib.
In that lib you can create a polyline, and give a line width.
You further specify how corners are filled. (BEVEL_JOIN, MITTER_JOIN)
The main question is wheter the path is drawn while driving or afterwords.
Afterwords is no problem.
To draw while driving might be a bit tricky to avoid to redraw the path each second.
When using the Path with moveTo and lineTo to create a polyline, then you can set a line width, and the graphics lib will do that all for you.
Then there will be no gaps, since it is a poly line.

android Dividing circle into N equal parts and know the coordinates of each dividing point

I have requirement that a circle should be divided into N equal parts based on number(2,3...n. But I want the coordinates of dividing points.
I have a circle whose centre(x,y) and radius(150) are known.
Question:
Is there any formula which gives me the coordinates of dividing points as shown in figure. Can anyone please tell me the formula. I want to implement it in Java.
Circle image for refrence:
I have already accepted answer... the formula works perfectly.
Here is the solution coded in Java. It will help other developers.
private int x[]; // Class variable
private int y[]; // Class variable
private void getPoints(int x0,int y0,int r,int noOfDividingPoints)
{
double angle = 0;
x = new int[noOfDividingPoints];
y = new int[noOfDividingPoints];
for(int i = 0 ; i < noOfDividingPoints ;i++)
{
angle = i * (360/noOfDividingPoints);
x[i] = (int) (x0 + r * Math.cos(Math.toRadians(angle)));
y[i] = (int) (y0 + r * Math.sin(Math.toRadians(angle)));
}
for(int i = 0 ; i < noOfDividingPoints ;i++)
{
Log.v("x",""+i+": "+x[i]);
Log.v("y",""+i+": "+y[i]);
}
}
Where x0 and y0 are co ordinates of circle's centre.and r is radius.
In my case:
Input x0 = 0 , y0 = 0 and r = 150 , noOfDividingPoints = 5
output
point1: (150,0)
point2: (46,142)
point3: (-121,88)
point4: (-121,-88)
point5: (46,-142)
You need to convert between polar and Cartesian coordinates. The angle you need is the angle between the (imaginary) vertical line that splits the circle in half and the line that connects the center with the circle's boundary. With this formula you can calculate the X and Y offsets from the center.
In your example image the first angle is 0, and the second one is 360/n. Each next is i*(360/n) where i is the index of the current line you need to draw. Applying this will give you the X and Y offsets in a clockwise order (and you can just add them to the X and Y coordinates of the center to find the coordinates of each point)
EDIT: some kind of pseudo-code:
//x0, y0 - center's coordinates
for(i = 1 to n)
{
angle = i * (360/n);
point.x = x0 + r * cos(angle);
point.y = y0 + r * sin(angle);
}

how to draw open ended circle in open gl es android

I need to draw a open ended circle as shown in image attached below
http://i49.tinypic.com/254y5bs.png
In the image the length of M should be greater than N, and the starting points of lines M and N are the center of circle. How can I draw an arc from the end point of N to M such that the arc looks linear in shape.
i am drawing the circle using the following code
for (int nR = N_IN_DEGREE; nR < M_IN_DEGREE && nCount < 360; nR++)
{
float fX = (float) Math.sin((float) nR * (Math.PI / 180)) + nR * 0.0008f;
float fY = (float) Math.cos((float) nR * (Math.PI / 180));
stVertexArray[nCount * 2] = fX;
stVertexArray[nCount * 2 + 1] = fY;
nCount++;
}
I get the open end circle from the angles N_IN_DEGREE to M_IN_DEGREE..but as I am increasing the value of fX by a factor of nR * 0.0008f , the complete circle is drawn only with 350 degrees,but i want 360..please run the code and see..my requirement is that I need to draw 2 lines n(length 0.8) and line m(length=1) from a single point and draw a arc from end point of n to end point of m and fill the arc with a color as well..
I can't make your code run, as there is not enough information, and I have trouble following your code.
But here is the basic idea, implemented in python.
import math
def genc(r1, r2, t1, t2, n):
dr = (r2 - r1)/n
dt = (t2 - t1)/n
x = []
y = []
for k in range(n):
r = r1 + k*dr
t = t1 + k*dt
x.append(r*math.cos(t))
y.append(r*math.sin(t))
return [x, y]
This is the output (plotted using matplotlib)
In [43]: a = circ.genc(1.0, 0.8, math.pi/2, 2*math.pi, 60)
In [44]: plot(a[0], a[1],'ro')
Out[44]: [<matplotlib.lines.Line2D at 0xb9285d0>]

Categories

Resources