i have an image that rotates around an arbitrary point. but i need 3 such images to rotate simultaneously
this is how i try to implement the same
private void rotateLogo(float degrees){
Matrix matrix1 = new Matrix();
//int radius = turntable.getWidth()/2;
double radians = degrees* (Math.PI/180);
double xcoordinate = 220 * Math.cos(radians)- 60;
double ycoordinate = 220 * Math.sin(radians) + 50;
matrix1.postRotate((int)radians, 220, 220);
// people image
FrameLayout.LayoutParams linLay = (FrameLayout.LayoutParams) peopleLogo.getLayoutParams();
linLay.bottomMargin = (int)ycoordinate + 10;
linLay.rightMargin = (int)xcoordinate + 10;
peopleLogo.setImageMatrix(matrix1);
peopleLogo.setLayoutParams(linLay);
rotateLogo2(degrees - 2);
}
private void rotateLogo2(float degrees){
double radians = degrees* (Math.PI/180);
double xcoordinate = 220 * Math.cos(radians)- 60;
double ycoordinate = 220 * Math.sin(radians) + 50;
// people image
FrameLayout.LayoutParams linLay = (FrameLayout.LayoutParams) serverLogo.getLayoutParams();
linLay.bottomMargin = (int)ycoordinate + 10;
linLay.rightMargin = (int)xcoordinate + 10;
serverLogo.setLayoutParams(linLay);
}
in the above code i reduced the angle and rotate the second image using the same code, but the image doesnt rotate, it just disappears on touch.
i also tried to take the layout params of the first image before rotation and apply the same to the second image, but this doesnt work too..
the image disappears on rotation though at times it appears and then disappears
can anyone help me as to where i could be wrong or suggest any other approaches for the same?
You can refactor the code
private void rotateLogo(View logo, float degrees){
Matrix matrix1 = new Matrix();
//int radius = turntable.getWidth()/2;
double radians = degrees* (Math.PI/180);
double xcoordinate = 220 * Math.cos(radians)- 60;
double ycoordinate = 220 * Math.sin(radians) + 50;
matrix1.postRotate((int)radians, 220, 220);
// people image
FrameLayout.LayoutParams linLay = (FrameLayout.LayoutParams) logo.getLayoutParams();
linLay.bottomMargin = (int)ycoordinate + 10;
linLay.rightMargin = (int)xcoordinate + 10;
if (logo isInstanceOf ImageView) {
logo.setImageMatrix(matrix1);
}
logo.setLayoutParams(linLay);
}
and call the method twice with different parameters..
rotateLogo(peopleLogo, degrees);
rotateLogo(serverLogo, degrees-2);
Related
This is a little bit complicated to explain, so apologies.
The basic requirement is annotator app on Android, which allows the user to draw over the desktop, take a snapshot and one or two other things.
When the app starts it shows a single icon. This can be moved about the desktop.
When this icon is single clicked (touch) 6 icons spread evenly centred around the central icon appear.
So far so good. Now we move the central icon, and re-calculate the positions of the 6 outer icons centred around the new position of the central icon.
What we find is the outer icons are off centre relative to the central icon. The displacement looks to be roughly equal (bot X and Y) by the position of the touch within the central icon.
I will attempt to draw what happens.
First when the touch point on the drag/move is in the centre, everything lines up perfectly:
When the touch point is to the right, the displacement is leftwards as below:
When the touch is at the bottom the displacement is upwards:
The position of the "x" relative to the icon is it seems from
int shiftX = event.getX();
int shiftY = event.getY();
The position of the moved icon is from :
view.getLocationInWindow(locWXY);
int X = locWXY[0];
int Y = locWXY[1];
So, the positions of the satellite icons are calculated as:
final double angle = 30.000;
final double rad = angle * Math.PI / 180.000;
final int radius = 100;
final int penX = (int) (X + radius * cos(rad) + shiftX);
final int penY = (int) (Y - radius * sin(rad) + shiftY);
final int clearX = X ;
final int clearY = (int) (Y - radius + shiftY);
final int closeX = (int) (X - radius * cos(rad) + shiftX);
final int closeY = (int) (Y - radius * sin(rad) + shiftY);
final int iFlipX = (int) (X - radius * cos(rad) + shiftX);
final int iFlipY = (int) (Y + radius * sin(rad) + shiftY);
final int sshotX = X + shiftX;
final int sshotY = (int) (Y + radius + shiftY);
final int iFolderX = (int) (X + radius * cos(rad) + shiftX);
final int iFolderY = (int) (Y + radius * sin(rad) + shiftY);
penLP= new RelativeLayout.LayoutParams(70, 70);
penLP.leftMargin = penX;
penLP.topMargin = penY;
imbBlackPen.setLayoutParams(penLP);
clearLP = new RelativeLayout.LayoutParams(70, 70);
clearLP .leftMargin = clearX;
clearLP .topMargin = clearY;
imbClearScreen.setLayoutParams(clearLP );
folderLP = new RelativeLayout.LayoutParams(70, 70);
folderLP .leftMargin = iFolderX ;
folderLP .topMargin = iFolderY;
imbFolder.setLayoutParams(folderLP );
sshotLP = new RelativeLayout.LayoutParams(70, 70);
sshotLP .leftMargin = sshotX ;
sshotLP .topMargin = sshotY;
imbScreenCapture.setLayoutParams(sshotLP );
iFlipLP = new RelativeLayout.LayoutParams(70, 70);
iFlipLP .leftMargin = iFlipX ;
iFlipLP .topMargin = iFlipY;
imbIflipChart.setLayoutParams(iFlipLP );
closeLP = new RelativeLayout.LayoutParams(70, 70);
closeLP .leftMargin = closeX ;
closeLP .topMargin = closeY;
imbClose.setLayoutParams(closeLP );
I have tried setting shiftX and shiftY to zero, calculating X and X + shiftX/2. All to no avail. The strange thing is that on a small 10 inch tablet with resolution 1920 x 1200 it looks almost perfect, but on a large 65 inch touch screen the displacement is extremely pronounced.
We must be missing something, but I cannot figure out what.
As commented above ...
Fixed. The icon position calculation code above needed to be executed on ACTION_UP as well as ACTION_DOWN. Refactored this as a method and called it on both these events.
I am trying to create dynamic buttons at the center of spesific areas of the ImageView. To figure out center of any area, I am using this function:
TextView createButton(int i, String[] boundingBoxArray) {
String[] coorArray = boundingBoxArray[i].split(",");
int[] coordinates = new int[4];
int x11 = Integer.parseInt(coorArray[0].replace(" ", ""));
int y11 = Integer.parseInt(coorArray[1].replace(" ", ""));
int x22 = Integer.parseInt(coorArray[2].replace(" ", ""));
int y22 = Integer.parseInt(coorArray[3].replace(" ", ""));
coordinates[0] = x11;
coordinates[1] = y11;
coordinates[2] = x22;
coordinates[3] = y22;
TextView buttonn = new TextView(context);
buttonn.setText(String.valueOf(i + 1));
buttonn.setTextSize(15);
buttonn.setId(i + 1);
buttonn.setBackgroundResource(R.drawable.circle);
RelativeLayout.LayoutParams rel_btn
= new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
Rect bounds = imageView.getDrawable().getBounds();
int scaledHeight = bounds.height();
int scaledWidth = bounds.width();
double scale;
double differWidth = 0;
double differHeight = 0;
imageViewHeight = imageView.getHeight();
imageViewWidth = imageView.getWidth();
if (scaledHeight > scaledWidth) {
scale = ((double) imageViewHeight / (double) scaledHeight);
differWidth = (imageViewWidth - (scaledWidth * scale)) / 2;
} else {
scale = ((double) imageViewWidth / (double) scaledWidth);
differHeight = (imageViewHeight - (scaledHeight * scale)) / 2;
}
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int swidth = displaymetrics.widthPixels;
int buttonWidth = swidth / 30;
double a = ((double) (x11 + x22) / 2) * scale - buttonWidth + differWidth;
double b = ((double) (y11 + y22) / 2) * scale - buttonWidth + differHeight;
rel_btn.leftMargin = (int) a;
rel_btn.topMargin = (int) b;
rel_btn.width = 2 * buttonWidth;
rel_btn.height = 2 * buttonWidth;
buttonn.setGravity(Gravity.CENTER);
buttonn.setLayoutParams(rel_btn);
return buttonn;
}
When the activity starts, this function is called in for loop (number of loop is depends on number of areas) to create buttons on the ImageView. When all buttons are created, user can click on one of any dynamic button to focus on the spesific area.
If the user click on any button, the createButton() function is called again (it doesnt necessary but it doesnt make an issue either) for some purposes.
The problem is height of ImageView is not fixed. At the first time of calling createButton() function, the height returns as greater than the normal height. Then if you call createButton() again, the height returns the normal value.
imageViewHeight = imageView.getHeight();
imageViewWidth = imageView.getWidth();
The class has 2-3 nested thread, so maybe this is cause of problem. But I tried lots of things like:
I used CountDownLatch to handle threads and functions
I used mImageView.post(new Runnable...) to be sure to call functions after imageView is created.
I called imageView.getHeight() lots of
different places, but nothing is changed.
I keep the expression long, because I couldn't decided if the information is enough to understand. And as you realize, English is not my native. Thank you.
Edit: I forgot to mention: Below API 19, everything is cool (getHeight() value is returning as the normal size, either at the first time of calling createButton() methor or later ). API 20 and above, I get this error.
I luckily found the solution.. I use fullscreen mode at my app, but I didn't use AreaSelectActivity in fullscreen. After activity opened, status bar is coming down in a while. That's why height is changed but length is not. I put AreaSelectActivity in fullscreen mode and bum ! it is fixed now.
I am trying to draw Circle with texture on it which should be stretched on all vertices.
The problem is that the result i get looks like this:
http://s14.postimg.org/3wyb74469/image.png
I have tried to draw triangle fan as it need to be , first coordinates at 0,0,0
And rest as needed:
http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
Also here is the same question and I couldn't get answer for my problem from it :
OpenGL ES, add texture to circle
Loading circle vertices coordinates function:
private final int mVerticesDataSize = 3;
private final int mNumberOfVertices = 180;
private final int mBytesPerFloat = 4;
private float[] vertices;
private FloatBuffer mVerticesBuff;
public void loadCircleVerticesBuff(Context mActivityContext){
mVerticesBuff = ByteBuffer.allocateDirect(mNumberOfVertices * mVerticesDataSize * mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
vertices = new float[mNumberOfVertices * mVerticesDataSize];
float theta = 0;
for (int i = 0; i < (mNumberOfVertices * mVerticesDataSize); i += 3) {
vertices[i] = (float) (((float) 5*Math.cos(theta)));
vertices[i + 1] = (float) ((float) 5*Math.sin(theta));
vertices[i + 2] = 0;
theta += Math.PI / 90;
}
mVerticesBuff.put(vertices);
mVerticesBuff.position(0);
}
Loading circle texture coordinates function:
private final int mTextureCoordinateDataSize = 3;
public void loadCircleTextureBuff(){
mCircleTextureCoordinatesBuff = ByteBuffer.allocateDirect(mNumberOfVertices * mTextureCoordinateDataSize * mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCircleTextureCoordinatesBuff.put(vertices);
mCircleTextureCoordinatesBuff.position(0);
}
The opengl function used to draw is :
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, mNumberOfVertices);
So solution found (: 1 very very importent thing i missed up / or openGL missed up.
Texture coordinates can be only in range of 0 to 1 .
So here is the trick/solution :
//Build vertices :
vertices[i] = (float) (((float) raduis*Math.cos(theta)))+raduis;
vertices[i + 1] = (float) ((float) raduis*Math.sin(theta))+raduis;
// Build texture :
for (int i = 0; i < (mNumberOfVertices * mVerticesDataSize); i += 3) {
vertices[i] = (vertices[i])/(raduis*2);
vertices[i + 1] = (vertices[i+1])/(raduis*2);
vertices[i + 2] = 0;
}
And here is the res :
http://s2.postimg.org/tno4jr4y1/image.png
Dont forget to flip texture vertices as i forgot (:
I'm in a tremendous bind with a last minute request on a consulting project I'm working on.
Essentially here is what I am trying to accomplish:
I have a surfaceview that draws a series of randomly sized circles. Each circle can have a radius from 50-100.
The x,y values are randomly generated along with a random radius
Each circle is created as an object representing that circle (x, y coord's and radius) and it is added to a list.
Once they are all created they are drawn.
The problem is I want to make sure none of these circles overlap.
I'm struggling a bit. This seems like it's shouldn't be all that difficult but it is for me unfortunately.
Here's my code so far (I know it's not close...be kind):
x = 100 + (int) (Math.random() * (mCanvasWidth - 200));
y = 100 + (int) (Math.random() * (mCanvasHeight - 200));
radius = 50 + (int) (Math.random() * 99);
color[0] = (float) (Math.random() * 360);
color[1] = 1;
color[2] = 1;
String radVal = String.valueOf(radius);
circle circ = new circle(x, y, radius, Color.HSVToColor(128, color), radVal);
boolean addit = true;
for (dot d : Dots) {
int leftSide = d.get_x() - radius;
int rightSide = d.get_x() + radius;
int xBoundary = x + radius;
int yBoundary = y + radius;
int exist_xLeft = d.get_x() - d.get_radius();
int exist_xRight = d.get_x() + d.get_radius();
int exist_yTop = d.get_y() - d.get_radius();
int exist_yBottom = d.get_y() + d.get_radius();
if ((xBoundary > exist_xLeft) && (xBoundary < exist_xRight))
{
if (yBoundary > (exist_yTop) && (yBoundary < exist_yBottom)) {
addit = false;
break;
}
}
}
if (addit)
circles.add(mdot);
if (circles.size() >= 5)
running = false;
Then it iterates the circles list and draws them to the canvas.
Any suggestions on where I'm failing in the collision detection?
You can detect if 2 circles are colliding like this:
Given:
centerpoints cx1,cy1 & cx2,cy2
and given radii r1 & r2,
Then you can determine if the 2 circles are colliding:
areColliding=((cx2-cx1)*(cx2-cx1)+(cy2-cy1)*(cy2-cy1))<((r1+r2)*(r1+r2));
I am trying to put a watermark/Image on another image, we can zoom in, zoom out, drag and rotate the watermark image by fingertouch. I am using Open CV library to rotate the image as suggested in this post
image rotation with opencv in android cuts off the edges of an image
It works fine until the rotation angle gets in between -75 to -105 and 75 to 105. In this range my image get cropped or it changes its position. I have tried several ways to get the right center point for the watermark image to put it in right position after rotating it but failed to do so.
Here is the code to rotate the image
// CALCULATE ROTATED WATERMARK IMAGE
private void CreateRotatedWaterMark()
{
// Means rotation took place
if (waterMarkAngle > 0 || waterMarkAngle < 0) {
// calculation for new width/height of rotated watermark image
newWidthHeight = boundingWaterMarkRect();
// remove when done testing
double pivotX = newWidthHeight[0] / 2; // 0 is width
double pivotY = newWidthHeight[1] / 2; // 1 is height
// rotating water image
org.opencv.core.Point center;
Size targetSize;
Mat targetMat;
// scalar is color/ RGBA , but alpha doesn't seem to work
Scalar colorScalar = new Scalar(255, 190, 190, 0);
double offsetX = (newWidthHeight[0] - scaledImage.width()) / 2;
double offsetY = (newWidthHeight[1] - scaledImage.height()) / 2;
// watermark's rotation lays somewhere in between 75' AND 105' OR
// -75' AND -105'
Log.e(TAG, "check => offsetX/offsetY Before => " + offsetX + " / "
+ offsetY);
if (offsetX < 0 || offsetY < 0) {
//this gets true when angle of rotation gets between -75 to -105 and 75 to 105
// change the offsets, now new newWidth < oldWidth AND newHeight
// > oldHeight (could be vice versa)
offsetX = (newWidthHeight[0] - scaledImage.height()) / 2;
offsetY = (newWidthHeight[1] - scaledImage.width()) / 2;
// Declaring new target size and target Mat, so rotated image is
// placed in new target Mat
targetSize = new Size(newWidthHeight[1], newWidthHeight[0]);
targetMat = new Mat(targetSize, scaledImage.type(), colorScalar);
// Getting the reference of center area from target Mat,
// below we're copying the actual image (scaledImage) to center
// position to target Mat
Mat waterSubmat = targetMat.submat((int) offsetX, (int) offsetX
+ scaledImage.height(), (int) offsetY, (int) offsetY
+ scaledImage.width());
scaledImage.copyTo(waterSubmat);
// Writing target image to sdcard, so we can know if its working
// properly, remove it when done with testing
Highgui.imwrite("mnt/sdcard/scaled90.png", targetMat);
Highgui.imwrite("mnt/sdcard/waterSubmat.png", waterSubmat);
Highgui.imwrite("mnt/sdcard/ScaledImage.png", scaledImage);
// targetSize is reverted again, so that target mat is pasted on
// canvas image
targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);
pivotX = newWidthHeight[0] / 2;
pivotY = newWidthHeight[1] / 2;
Log.e(TAG, "check => pivotX/pivotY => " + pivotX + " / "
+ pivotY);
Log.e(TAG, "check => Angle => " + waterMarkAngle);
center = new org.opencv.core.Point(pivotX, pivotY);
} else {
center = new org.opencv.core.Point(pivotX, pivotY);
targetSize = new Size(newWidthHeight[0], newWidthHeight[1]);
targetMat = new Mat(targetSize, scaledImage.type(), colorScalar);
// Centralizing watermark
Mat waterSubmat = targetMat.submat((int) offsetY, (int) offsetY
+ scaledImage.height(), (int) offsetX, (int) offsetX
+ scaledImage.width());
scaledImage.copyTo(waterSubmat);
Highgui.imwrite("mnt/sdcard/scaled10.png", targetMat);
}
Mat rotImage = Imgproc.getRotationMatrix2D(center, waterMarkAngle,
1.0); // 1.0 means scale 100%
Highgui.imwrite("mnt/sdcard/Rotated90.png", rotImage);
// Mat waterSubmat1 = rotImage.submat(0, scaledImage.height(), 0,
// scaledImage.width());
Mat resultMat = new Mat();
// scalar for color, Imagproc.warAffine actually rotates the final
// watermark on canvas image
colorScalar = new Scalar(122, 22, 22);
Imgproc.warpAffine(targetMat, resultMat, rotImage, targetSize,
Imgproc.INTER_LINEAR, Imgproc.BORDER_CONSTANT, colorScalar);
Log.i(TAG, "check MATRIX = " + resultMat.toString());
Log.i(TAG, "check Result Mat " + resultMat.size().toString());
scaledImage = resultMat.clone();
Highgui.imwrite("mnt/sdcard/Result100.png", targetMat);
// Log.i(TAG, "check Result postion = "+ resultMat.r);
// WRITE SOME TEXT ON CANVAS IMAGE, its not rotated
Core.putText(scaledImage, "angle: " + waterMarkAngle,
new org.opencv.core.Point(0, scaledImage.height() / 2),
Core.FONT_HERSHEY_TRIPLEX, 2, new Scalar(23, 12, 450, 0.5),
2); // CV_BLUR_NO_SCALE
} else {
// CHANGE OPACITY OF WATERMARK IMAGE
// Core.multiply(scaledImage, new Scalar(1, 1, 1, 0.6),
// scaledImage);
// REMOVE THIS WHEN DONE TESTING
// Highgui.imwrite("mnt/sdcard/opacityWatermark.png",scaledImage);
}
}
private double[] boundingWaterMarkRect() {
// -----NEW CALCULATION------
// so we always get positive angle
double tempAngle = ((waterMarkAngle < 0 ? 360 - waterMarkAngle : waterMarkAngle) % 360);
double radians = Math.toRadians(tempAngle);
Log.i(TAG, "check => radian => "+ radians);
double sin = Math.abs(Math.sin(radians));
double cos = Math.abs(Math.cos(radians));
double newWidth = (double) (scaledImage.width() * cos + scaledImage.height() * sin);
double newHeight = (double) (scaledImage.width() * sin + scaledImage.height() * cos);
double[] wh = {newWidth, newHeight};
return wh;
}
Following are two images first one is right and the other is rotated wrong
Anyone have got solution for it?