In my android app, I need to deform the image from one point to the other point.
It should seems like that
the origin point A and the B is the new position of A
the result may like that
I have try to use the "drawBitmapMesh" function to make it possible, but did not reach, here is the wrap code:
public void warp(float startX, float startY, float endX, float endY) {
float ddPull = (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY);
float dPull = (float) Math.sqrt(ddPull);
for (int i = 0; i < (COUNTS * 2); i += 2) {
float dx = orig[i] - startX;
float dy = orig[i + 1] - startY;
float dd = dx * dx + dy * dy;
float d = (float) Math.sqrt(dd);
// do deformation when the point is in the circle
if (d < cirR) {
double e =(cirR * cirR - dd) * (cirR * cirR - dd) / ((cirR * cirR - dd + dPull * dPull) * (cirR * cirR - dd + dPull * dPull));
double pullX = e * (endX - startX);
double pullY = e * (endY - startY);
verts[i] = (float) (orig[i] + pullX);
verts[i + 1] = (float) (orig[i + 1] + pullY);
}
}
invalidate();
}
At last I solve it by myself, i use the GPUimage for Android and write a customized filter by GLSL, it works good~!
Related
First thing I have drawn the three lines of the hexagon width specific width then I have drawn the six points using this formula section = 2 * PI / NumberOfPoints. Here is the pic of lines I have drawn:
what I want is to draw a triangle between every two lines which will be 6 triangles. Here is the pic when I drew the triangles:
My problem is I want the triangle to be drawn between the lines, not above them which mean the triangle should not overlaps the line.
Here is how I drew the lines:
for (int i = 1; i <= 6; i++) {
float eX = (float) (x + radius * Math.cos(section * i));
float eY = (float) (y + radius * Math.sin(section * i));
linesPaint.setShader(new LinearGradient(x, y, eX, eY, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.MIRROR));
canvas.drawLine(x, y, eX, eY, linesPaint);
}
and here is how I drew the triangles
for (int i = 1; i <= 6; i++) {
TriangleColor triangleColor = triangleColors.get(i - 1);
trianglesPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), triangleColor.firstColor, triangleColor.secondColor, Shader.TileMode.REPEAT));
float x1 = (float) (x + radius * Math.cos(section * i));
float y1 = (float) (y + radius * Math.sin(section * i));
float x2 = (float) (x + radius * Math.cos(section * (i + 1)));
float y2 = (float) (y + radius * Math.sin(section * (i + 1)));
trianglesPath.moveTo(x, y);
trianglesPath.lineTo(x1, y1);
trianglesPath.lineTo(x2, y2);
trianglesPath.lineTo(x, y);
canvas.drawPath(trianglesPath, trianglesPaint);
trianglesPath.reset();
}
Can anyone help me with the formula? Thanks in advance.
I assume that you have lines with thickness 2d
To avoid overwriting these lines, you can shift the central point for every triangle by dstance d/sin(30) = 2*d in direction of bisector between two lines
Perhaps also you need to diminish radius (length of triangle side along the line)
newradius = radius - d*sqrt(3) - d * sqrt(3)/3
for (int i = 1; i <= 6; i++) {
cx = x + 2 * d * Math.cos(section * (i + 0.5));
cy = x + 2 * d * Math.sin(section * (i + 0.5));
float x1 = (float) (cx + newradius * Math.cos(section * i)); /
//and similar for other coordinates
trianglesPath.moveTo(cx, cy);
trianglesPath.lineTo(x1, y1);
...
The arrow head with stroke working fine in canvas, but the filled arrow head is not drawing at the right position ,Here is my code for draw arrow.
private void drawArrow(Point startPoint, Point endPoint, Paint paint, Canvas mCanvas) {
Path mPath = new Path();
float deltaX = endPoint.x - startPoint.x;
float deltaY = endPoint.y - startPoint.y;
//float frac = (float) 0.1;
int ARROWHEAD_LENGTH = 15;
float sideZ = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
float frac = ARROWHEAD_LENGTH < sideZ ? ARROWHEAD_LENGTH / sideZ : 1.0f;
float point_x_1 = startPoint.x + (float) ((1 - frac) * deltaX + frac * deltaY);
float point_y_1 = startPoint.y + (float) ((1 - frac) * deltaY - frac * deltaX);
float point_x_2 = endPoint.x;
float point_y_2 = endPoint.y;
float point_x_3 = startPoint.x + (float) ((1 - frac) * deltaX - frac * deltaY);
float point_y_3 = startPoint.y + (float) ((1 - frac) * deltaY + frac * deltaX);
mPath.moveTo(point_x_1, point_y_1);
mPath.lineTo(point_x_2, point_y_2);
mPath.lineTo(point_x_3, point_y_3);
//mPath.lineTo(point_x_1, point_y_1);
//mPath.lineTo(point_x_1, point_y_1);
mCanvas.drawPath(mPath, paint);
invalidate();
}
to resolve this issue, I have placed the end line to the center of triangle.
You can do it with this formula :
float endLineX = (point_x_1 + point_x_2 + point_x_3) / 3;
float endLineY = (point_y_1 + point_y_2 + point_y_3) / 3;
VoilĂ
I'm trying to make an animation on my android application.
I have a list of View I want to draw every 10 ms to have a smooth animations.
class CircularAnimationSector extends View{
private double scale;
private double circularPosition;
private double circularLength;
private double sectionRadiusRatio;
private double circularSpeed;
private int color;
private Paint paint = new Paint();
private ICircular iCircular;
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Path path = new Path();
int width = this.getWidth();
// int height = this.getHeight();
Point center = new Point((int)(width / 2.0f), (int)(width / 2.0f));
int innerWidthRadius = (int) (this.iCircular.GetViewSize() / 2.0f);
float startRadius = (float)(innerWidthRadius * this.iCircular.GetStartRatio());
float endRadius = (float)(startRadius + this.scale * (this.sectionRadiusRatio - this.iCircular.GetStartRatio()) * innerWidthRadius);
float startAngle = (float)(this.circularPosition - this.circularLength / 2.0f);
float endAngle = (float)(this.circularPosition + this.circularLength / 2.0f);
Point p1 = new Point((int) (center.x + startRadius * Math.cos(startAngle)), (int) (center.y + startRadius * Math.sin(startAngle)));
Point p3 = new Point((int) (center.x + endRadius * Math.cos(endAngle)), (int) (center.y + endRadius * Math.sin(endAngle)));
// PATH DRAWING
path.moveTo((float) (p1.x), (float) (p1.y));
path.arcTo(new RectF(center.x - startRadius, center.y - startRadius, center.x + startRadius, center.y + startRadius), (float) (startAngle * 180 / Math.PI), (float) ((endAngle - startAngle) * 180 / Math.PI));
path.lineTo((float) (p3.x), (float) (p3.y));
path.arcTo(new RectF(center.x - endRadius, center.y - endRadius, center.x + endRadius, center.y + endRadius), (float) (endAngle * 180 / Math.PI), (float) ((startAngle - endAngle) * 180 / Math.PI));
path.lineTo((float) (p1.x), (float) (p1.y));
canvas.drawPath(path, this.paint);
this.circularPosition += this.circularSpeed;
}
}
But it seems that the animation is not as smooth as expected and the application lag a little.
Do you have any advice to optimize my animation ?
I just want to draw a view every 10 ms (for instance) and then upadte its position and draw it again around a circle.
I am rendering video on GLSurfaceView by openGL. The openGL portion is written on C++ in native portion. This is my render routine:
void VideoRenderOpenGL2::Render(const unsigned char *pData)
{
......................
// GL_OPERATION is a macro, nothing special
GL_OPERATION(glUseProgram(m_program))
UpdateTextures(pData); // other routine, I will post the function if needed
bool bClear = true;
float vpx = 0.0f;
float vpy = 0.0f;
float vpw = 1.0f;
float vph = 1.0f;
int nOrientation = 0;
float uLeft, uRight, vTop, vBottom;
uLeft = vBottom = 0.0f;
uRight = m_uvx;
vTop = m_uvy;
GLfloat squareUvs[] = {
uLeft, vTop,
uRight, vTop,
uLeft, vBottom,
uRight, vBottom
};
if (bClear) {
GL_OPERATION(glViewport(0, 0, m_nDisplayWidth, m_nDisplayHeight))
GL_OPERATION(glClearColor(0, 0, 0, 1))
GL_OPERATION(glClear(GL_COLOR_BUFFER_BIT))
}
GLfloat squareVertices[8];
// drawing surface dimensions
int screenW = m_nDisplayWidth;
int screenH = m_nDisplayHeight;
if (nOrientation == 90 || nOrientation == 270) {
screenW = m_nDisplayHeight;
screenH = m_nDisplayWidth;
}
int x,y,w,h;
// Fill the smallest dimension, then compute the other one using the image ratio
if (screenW <= screenH) {
float ratio = m_nTextureHeight / (float)m_nTextureWidth;
w = screenW * vpw;
h = w * ratio;
if (h > screenH) {
w *= screenH /(float) h;
h = screenH;
}
x = vpx * m_nDisplayWidth;
y = vpy * m_nDisplayHeight;
} else {
float ratio = m_nTextureWidth / (float)m_nTextureHeight;
h = screenH * vph;
w = h * ratio;
if (w > screenW) {
h *= screenW / (float)w;
w = screenW;
}
x = vpx * screenW;
y = vpy * screenH;
}
// here m_nDisplayWidth = 5536, m_nDisplayHeight = 3114, w = 5536, h = 3114, x = 0, y = 0, screenW = 5536, screenH = 3114, m_nTextureWidth = 1280, m_nTextureHeight = 720
squareVertices[0] = (x - w * 0.5) / screenW - 0.;
squareVertices[1] = (y - h * 0.5) / screenH - 0.;
squareVertices[2] = (x + w * 0.5) / screenW - 0.;
squareVertices[3] = (y - h * 0.5) / screenH - 0.;
squareVertices[4] = (x - w * 0.5) / screenW - 0.;
squareVertices[5] = (y + h * 0.5) / screenH - 0.;
squareVertices[6] = (x + w * 0.5) / screenW - 0.;
squareVertices[7] = (y + h * 0.5) / screenH - 0.;
GL_OPERATION(glViewport(0, 0, m_nDisplayWidth, m_nDisplayHeight))
GLfloat mat[16];
#define VP_SIZE 1.0f
float vpDim = VP_SIZE / (2 * m_scaleFactor);
#define ENSURE_RANGE_A_INSIDE_RANGE_B(a, aSize, bMin, bMax) \
if (2 * aSize >= (bMax - bMin)) \
a = 0; \
else if ((a - aSize < bMin) || (a + aSize > bMax)) { \
float diff; \
if (a - aSize < bMin) diff = bMin - (a - aSize); \
else diff = bMax - (a + aSize); \
a += diff; \
}
float zoom_cx = 0.0f;
float zoom_cy = 0.0f;
ENSURE_RANGE_A_INSIDE_RANGE_B(zoom_cx, vpDim, squareVertices[0], squareVertices[2])
ENSURE_RANGE_A_INSIDE_RANGE_B(zoom_cy, vpDim, squareVertices[1], squareVertices[7])
LoadOrthographicMatrix(
zoom_cx - vpDim,
zoom_cx + vpDim,
zoom_cy - vpDim,
zoom_cy + vpDim,
0, 0.5, mat);
GL_OPERATION(glUniformMatrix4fv(m_uniforms[UNIFORM_PROJ_MATRIX], 1, GL_FALSE, mat))
#define degreesToRadians(d) (2.0 * 3.14157 * d / 360.0)
float rad = degreesToRadians(nOrientation);
GL_OPERATION(glUniform1f(m_uniforms[UNIFORM_ROTATION], rad))
GL_OPERATION(glActiveTexture(GL_TEXTURE0))
GL_OPERATION(glBindTexture(GL_TEXTURE_2D, m_textures[Y]))
GL_OPERATION(glUniform1i(m_uniforms[UNIFORM_TEXTURE_Y], 0))
GL_OPERATION(glActiveTexture(GL_TEXTURE1))
GL_OPERATION(glBindTexture(GL_TEXTURE_2D, m_textures[U]))
GL_OPERATION(glUniform1i(m_uniforms[UNIFORM_TEXTURE_U], 1))
GL_OPERATION(glActiveTexture(GL_TEXTURE2))
GL_OPERATION(glBindTexture(GL_TEXTURE_2D, m_textures[V]))
GL_OPERATION(glUniform1i(m_uniforms[UNIFORM_TEXTURE_V], 2))
GL_OPERATION(glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices))
GL_OPERATION(glEnableVertexAttribArray(ATTRIB_VERTEX))
GL_OPERATION(glVertexAttribPointer(ATTRIB_UV, 2, GL_FLOAT, 1, 0, squareUvs))
GL_OPERATION(glEnableVertexAttribArray(ATTRIB_UV))
GL_OPERATION(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4))
}
And this is LoadOrthographicMatrix:
void VideoRenderOpenGL2::LoadOrthographicMatrix(float left, float right, float bottom, float top, float near, float far, float* mat)
{
float r_l = right - left;
float t_b = top - bottom;
float f_n = far - near;
float tx = - (right + left) / (right - left);
float ty = - (top + bottom) / (top - bottom);
float tz = - (far + near) / (far - near);
mat[0] = (2.0f / r_l);
mat[1] = mat[2] = mat[3] = 0.0f;
mat[4] = 0.0f;
mat[5] = (2.0f / t_b);
mat[6] = mat[7] = 0.0f;
mat[8] = mat[9] = 0.0f;
mat[10] = -2.0f / f_n;
mat[11] = 0.0f;
mat[12] = tx;
mat[13] = ty;
mat[14] = tz;
mat[15] = 1.0f;
}
Suppose, my device dimension is 1080 x 1557 and I am trying to render 2768 x 1557 (height equal to device height and corresponding width keeping aspect ratio with 1280 x 720) sized video on the GLSurfaceView. Everything works fine so far and Render(const unsigned char *pData) is properly rendering and glViewport(0, 0, m_nDisplayWidth, m_nDisplayHeight) is working fine.
But when I want to load video twice the size of 2768 x 1557 I mean 5536 x 3114 the video shinked/congested (not truncated) across X axis. The Render(...) is drawing the full contents of video, but not using the full canvas. I can't figure it out what's wrong here. Why the video is congested across X axis?
It is to be noted that, the video is rendered more congested when I increased the width & height more than 2 times. Its okay till 2768 x 1557
You may be exceeding limits of your OpenGL implementation. Particularly, the maximum texture size and maximum viewport dimensions could come into play.
To query the maximum texture size, use:
GLint maxTexSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
and for the maximum viewport dimensions:
GLint viewportDims[2] = {0};
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewportDims);
Typical values for these limits are as low as 2K for current low end devices, and possibly even lower for older devices. 4K and 8K are very common for current mainstream devices. Recent high end mobile GPUs support sizes up to 16K.
So before you try sizes over 4K, you should definitely check these limits. It's very likely that your 5536x3114 size will be beyond the limit of some fairly recent devices.
I am using http://www.codeproject.com/Articles/146145/Android-3D-Carousel code to create a vertical carousel view.i can see the vertical carousel using below changes in the code but center item is not properly placed in the screen and if the list items size increased, diameter moves upwards.
private void setUpChild(CarouselImageView child, int index, float angleOffset) {
// Ignore any layout parameters for child, use wrap content
addViewInLayout(child, -1 /*index*/, generateDefaultLayoutParams());
child.setSelected(index == mSelectedPosition);
int h;
int w;
if (mInLayout)
{
h = (getMeasuredHeight() - getPaddingBottom()-getPaddingTop())/3;
w = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()/3;
}
else
{
h = (getMeasuredHeight() - getPaddingBottom()-getPaddingTop())/3;
w = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()/3;
}
child.setCurrentAngle(angleOffset);
// modify the diameter.
Calculate3DPosition(child, w*(getAdapter().getCount()/4), angleOffset);
// Measure child
child.measure(w, h);
int childLeft;
// Position vertically based on gravity setting
int childTop = calculateTop(child, true);
childLeft = 0;
child.layout(childLeft, childTop, w, h);
}
change in calculate3position function as below
float x = (float) (-diameter/2 * Math.cos(angleOffset) * 0.00001);
float z = diameter/2 * (1.0f - (float)Math.cos(angleOffset));
float y = (float) (diameter/2 * Math.sin(angleOffset)) + diameter/2 - child.getWidth();
child.setX(x);
child.setZ(z);
child.setY(y);
I think that this calculation:
float x = (float) (-diameter/2 * Math.cos(angleOffset) * 0.00001);
float z = diameter/2 * (1.0f - (float)Math.cos(angleOffset));
float y = (float) (diameter/2 * Math.sin(angleOffset)) + diameter/2 - child.getWidth();
should be this:
float x = 0.0f
float z = diameter/2.0f * (1.0f - (float)Math.cos(angleOffset));
float y = (diameter/2.0f * Math.sin(angleOffset)) + diameter/2.0f - child.getHeight()/2.0f;
Your x position should always be zero, and your y position should be based on the sin, and should be offset by 1/2 of the height of the child instead of 1/2 of the width.
Hello try this code and replace with this code in your Calculate3DPosition method
angleOffset = angleOffset * (float) (Math.PI / 180.0f);
float y = (float) (((diameter * 60) / 100) * Math.sin(angleOffset)) + ((diameter * 50) / 100);
float z = diameter / 2 * (1.0f - (float) Math.cos(angleOffset));
float x = (float) (((diameter * 5) / 100) * Math.cos(angleOffset) * 0.3);
child.setItemX(x);
child.setItemZ((z * 30) / 100);
child.setItemY(-(y));
its solve my problem please try this one