Placing objects on Face based on landmark positions google vision api - java

I am trying to detect eyes and put glasses over eyes using Google Mobile Vision api.
here is what i have tried
Face face = faces.valueAt(0);
Landmark leftEye = null;
Landmark rightEye = null;
for (Landmark landmark : face.getLandmarks())
{
if (landmark.getType() == Landmark.LEFT_EYE)
leftEye = landmark;
else if (landmark.getType() == Landmark.RIGHT_EYE)
rightEye = landmark;
}
if(leftEye != null && rightEye != null)
{
double diff = leftEye.getPosition().x * mImageView.scale - rightEye.getPosition().x * mImageView.scale - 15;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.raw.glasses1);
int width = (int) pxFromDp(this, (float) diff);
final double viewWidthToBitmapWidthRatio = (double)width / (double) bitmap.getWidth();
int height = (int) (bitmap.getHeight() * viewWidthToBitmapWidthRatio);
filterImg.getLayoutParams().width = width;
filterImg.getLayoutParams().height = height;
filterImg.invalidate();
float x = (rightEye.getPosition().x + 15) * mImageView.scale;
float y = (rightEye.getPosition().y + face.getPosition().y) * mImageView.scale;
filterImg.setX(x);
filterImg.setY(y);
filterImg.setRotation(face.getEulerY());
filterImg.setImageResource(rawFile);
mImageView.setData(bitmap, faces);
}
else
Toast.makeText(ImageFiltersActivity.this, "Unable to parse landmarks", Toast.LENGTH_SHORT).show();
This is my code copied from google sources
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmap != null && mFaces != null) {
double deviceScale = drawBitmapToDeviceSize(canvas);
drawFaceDetectionBox(canvas, deviceScale);
}
}
private double drawBitmapToDeviceSize(Canvas canvas) {
double viewWidth = canvas.getWidth();
double viewHeight = canvas.getHeight();
double imageWidth = mBitmap.getWidth();
double imageHeight = mBitmap.getHeight();
scale = (float) Math.min(viewWidth / imageWidth, viewHeight / imageHeight);
Rect bitmapBounds = new Rect(0, 0, (int) (imageWidth * scale), (int) (imageHeight * scale));
return scale;
}
private void drawFaceDetectionBox(Canvas canvas, double deviceScale)
{
Paint paint = new Paint();
paint.setColor(Color.YELLOW);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
for (int i = 0; i < mFaces.size(); ++i)
{
Face face = mFaces.valueAt(i);
float x1 = (float) (face.getPosition().x * deviceScale);
float y1 = (float) (face.getPosition().y * deviceScale);
float x2 = (float) (x1 + face.getWidth() * deviceScale);
float y2 = (float) (y1 + face.getHeight() * deviceScale);
for (Landmark landmark : face.getLandmarks())
{
int type = landmark.getType();
float m1 = (float) (landmark.getPosition().x * deviceScale);
float m2 = (float) (landmark.getPosition().y * deviceScale);
canvas.drawCircle(m1, m2, 2, paint);
}
canvas.drawRect(x1, y1, x2, y2,
paint);
}
}
Result is
float m1 = (float) (landmark.getPosition().x * deviceScale);
float m2 = (float) (landmark.getPosition().y * deviceScale);
canvas.drawCircle(m1, m2, 2, paint);
works fine but when i move my imageView
float x = (rightEye.getPosition().x + 15) * mImageView.scale;
float y = (rightEye.getPosition().y + face.getPosition().y) * mImageView.scale;
filterImg.setX(x);
filterImg.setY(y);
the imageview is misplaced and is NOT on eyes.
Anyone can explain or help what am i missing?

double diff = leftEye.getPosition().x * mImageView.scale - rightEye.getPosition().x * mImageView.scale - 15;
remove -15 and try again.

Related

create percentage square in java instead circles

I am working in a existing project for an amazfit watchface. Code is based in java. The question is: In original project, for show battery, steps and sport percentage, show three circles. My idea is to draw a rectangle (or a line) instead the original circle. The problem is I am new programming in java and I don´t know for change this without FC app.
this watch has two screens: one active and other in stand-by mode (8colors only)
active mode draws circle, standby mode works with an png image.
This is the code (for circles):
package es.xxxx.xxxx.widget;
private final float startAngleBattery = 30;
private final float arcSizeBattery = 360 - startAngleBattery - startAngleBattery;
#Override
public void init(Service service) {
this.thickness = (int) service.getResources().getDimension(R.dimen.xxxx_circles_thickness);
this.textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.textPaint.setTypeface(ResourceManager.getTypeFace(service.getResources(), ResourceManager.Font.BEBAS_NEUE));
this.textPaint.setTextSize(service.getResources().getDimension(R.dimen.xxxx_circles_font_size));
this.textPaint.setColor(service.getResources().getColor(R.color.xxxx_time_colour));
this.textPaint.setTextAlign(Paint.Align.CENTER);
this.ring = new Paint(Paint.ANTI_ALIAS_FLAG);
this.ring.setStrokeCap(Paint.Cap.ROUND);
this.ring.setStyle(Paint.Style.STROKE);
this.ring.setStrokeWidth(this.thickness);
this.circle = new Paint(Paint.ANTI_ALIAS_FLAG);
this.circle.setColor(Color.BLACK);
this.circle.setStrokeWidth(1f);
this.circle.setStyle(Paint.Style.STROKE);
#Override
public void draw(Canvas canvas, float width, float height, float centerX, float centerY) {
int count = canvas.save();
int radius = Math.round(Math.min(width / 2, height / 2)) - this.thickness;
RectF oval = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
// rotate from 0 to 270 degrees
canvas.rotate(90, centerX, centerY);
this.ring.setColor(this.backgroundColour);
canvas.drawArc(oval, startAngleBattery, arcSizeBattery, false, ring);
if (batterySweepAngle != null) {
float px = getPointX(oval, centerX, startAngleBattery, batterySweepAngle);
float py = getPointY(oval, centerY, startAngleBattery, batterySweepAngle);
this.ring.setColor(this.batteryColour);
canvas.drawArc(oval, startAngleBattery, batterySweepAngle, false, ring);
canvas.drawCircle(px, py, this.thickness / 3f, circle);
canvas.drawCircle(px, py, this.thickness / 6f, circle);
}
canvas.restoreToCount(count);
if (this.batteryData != null) {
String text = String.format("%02d", this.batteryData.getLevel() * 100 / this.batteryData.getScale());
canvas.drawText(text, batteryTextLeft, batteryTextTop, textPaint);
}
}
#Override
public void onDataUpdate(DataType type, Object value) {
switch (type) {
case BATTERY:
onBatteryData((Battery) value);
break;
}
}
#Override
public List<DataType> getDataTypes() {
return Arrays.asList(DataType.BATTERY);
private void onBatteryData(Battery battery) {
this.batteryData = battery;
if (batteryData == null) {
this.batterySweepAngle = 0f;
} else {
float scale = batteryData.getLevel() / (float) batteryData.getScale();
this.batterySweepAngle = Math.min(arcSizeBattery, arcSizeBattery * scale);
}
}
private RectF nextOval(RectF oval) {
oval.left = oval.left + this.thickness + MARGIN;
oval.top = oval.top + this.thickness + MARGIN;
oval.right = oval.right - this.thickness - MARGIN;
oval.bottom = oval.bottom - this.thickness - MARGIN;
return oval;
}
private float getPointX(RectF oval, float cx, float startAngle, float sweepAngle) {
float width = oval.right - oval.left;
return (float) (cx + (width / 2D) * Math.cos((sweepAngle + startAngle) * Math.PI / 180));
}
private float getPointY(RectF oval, float cy, float startAngle, float sweepAngle) {
float height = oval.bottom - oval.top;
return (float) (cy + (height / 2D) * Math.sin((sweepAngle + startAngle) * Math.PI / 180));
}
#Override
public List<SlptViewComponent> buildSlptViewComponent(Service service) {
Typeface timeTypeFace = ResourceManager.getTypeFace(service.getResources(), ResourceManager.Font.BEBAS_NEUE);
SlptLinearLayout power = new SlptLinearLayout();
power.alignX = 2;
power.alignY = 2;
power.add(new SlptPowerNumView());
power.setTextAttrForAll(
service.getResources().getDimension(R.dimen.xxxx_circles_font_size_slpt),
-1,
timeTypeFace
);
power.setStart(
(int) service.getResources().getDimension(R.dimen.xxxx_battery_text_left_slpt),
(int) service.getResources().getDimension(R.dimen.xxxx_battery_text_top_slpt));
SlptPowerArcAnglePicView powerArcView = new SlptPowerArcAnglePicView();
powerArcView.setImagePicture(Util.assetToBytes(service, "battery_splt.png"));
powerArcView.start_angle = (int) startAngleBattery + 180 - 3;
powerArcView.full_angle = (int) arcSizeBattery + 6;
return Arrays.asList(power, powerArcView);
}
}
Thanks in advance.
For anyone still searching...
You can draw the rectangular in the "draw" function that runs in loop constantly when screen is on, however, screen off (SLPT mode) uses ingenic's libraries to draw (function buildSlptViewComponent) and there is the real problem.
I don't want to get into details because it would be pages, so have a look at GreatFit project.

Javelin throw simulation calculation of slope of tangent line at every javelin trajectory point

I am trying to simulate javelin throw on android. I calculate slope of tangent line in every point of javelin trajectory. To calculate trajectory coordinates I am using Projectile motion equations
x = (int) (x0 + v0 * t * Math.cos(radians)); //for coordinate x
and
y = (int) (y0 - v0 * t * Math.sin(radians) + 0.5 * g * t * t);
To calculate slope of tangent line to javelin trajectory I derivated this equation with respect to x:
y = Math.tan(radians) * x - g / (2 * Math.pow(v0, 2) * Math.pow(Math.cos(radians), 2)) * x^2
dy = Math.tan(radians) - (g * x) / (Math.pow(v0, 2) * Math.pow(Math.cos(radians), 2))
Problem is, that it works correctly with elevation angle < than approximately 60 degrees.
If elevation angle is bigger, it doesn't calculate correct slope.
Here is the code:
public class ThrowJavelin extends ImageView {
private Context mContext;
int x0 = -1;
int y0 = -1;
int x = x0;
int y = y0;
private Handler h;
private final int FRAME_RATE = 5;
private double t = 0;
private float g = 9.81f;
//initial velocity
private int v0;
//elevation angle in radians
private double radians;
//javelin current angle in degrees
private double javelin_angle;
public ThrowJavelin(Context context, AttributeSet attr) { super(context, attr); }
public ThrowJavelin(Context context, AttributeSet attrs, int defStyleAttr){ super(context, attrs, defStyleAttr); }
public ThrowJavelin(Context context, Bundle args) {
super(context);
mContext = context;
h = new Handler();
//input values
v0 = args.getInt("velocity");
radians = args.getDouble("radians");
}
private Runnable r = new Runnable() {
#Override
public void run() {
invalidate();
}
};
protected void onDraw(Canvas c) {
Bitmap javelin = BitmapFactory.decodeResource(getResources(), R.drawable.jav);
DerivativeStructure alpha = null;
if (x < 0 && y < 0) {
x0 = 0;
y0 = c.getHeight() - 200;
x = x0;
y = y0;
javelin = rotateBitmap(javelin, (float) Math.toDegrees(radians));
} else if (y > y0) { //reset to beginning
x = x0;
y = y0;
t = 0;
javelin = rotateBitmap(javelin, (float) Math.toDegrees(radians));
} else {
//calculate current coordinates (depends on t)
x = (int) (x0 + v0 * t * Math.cos(radians));
y = (int) (y0 - v0 * t * Math.sin(radians) + 0.5 * g * t * t);
if (x == 0) {
javelin_angle = Math.toDegrees(radians);
} else {
// dy of 3rd equation
javelin_angle = Math.toDegrees(Math.tan(radians) - (g * x) / (Math.pow(v0, 2) * Math.pow(Math.cos(radians), 2)));
}
javelin = rotateBitmap(javelin, javelin_angle);
t += 0.3;
}
c.drawBitmap(javelin, x, y, null);
h.postDelayed(r, FRAME_RATE);
}
public Bitmap rotateBitmap(Bitmap image, double angle){
float alpha = (float) angle;
Matrix mat = new Matrix();
System.out.println(-alpha);
mat.postRotate(-alpha);
return Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), mat, true);
}
}
I really don't understand, why ot doesn't work correctly for bigger angles. Any ideas please?
Firstly, your solution for y(x) seems to drop a few variables (e.g. x0). Here is the full solution:
y(x) = y0 + (0.5 * g * (x - x0)^2)/(v0^2 * cos(radians)^2) - (x - x0) * tan(radians)
The derivative with respect to x is:
dy/dx = (g * (x - x0)) / (v0^2 * cos^2(radians)) - tan(radians)
Your solution looks very similar except that its y-axis is inverted and it misses the initial positions.
The angle that corresponds to this derivative is its arctangens:
double c = Math.cos(radians);
javelin_angle = Math.toDegrees(Math.atan((g * (x - x0) / (v0 * v0 * c * c) - Math.tan(radians)));
I assume, there was a reason why you swapped the y-axis. So you may do that again in this formula.
The reason why your formula worked for small angles is that the arctangens is close to the identity for small angles (identity in red, arctangens in blue):

How to draw new circle on touch and remove previous circle

I can create circle on touch but can not remove the previous one. I have manage to remove the very first circle but the code is poor and it does not really work as I want. I like to draw circle every time I touch the screen and remove the previous circle . So the screen starts with a circle and as I will touch a new position the previous should be removed and there will be a new one.So how to do that part?
Here is my work:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
Display display = new Display(this);
display.init();
display.backPaint.setColor(Color.WHITE);
setContentView(display);
}
static class Display extends View {
ArrayList<Point> points = new ArrayList();
int touch1_x=700;
int touch1_y=700;
Paint backPaint;
Paint circlePaint;
Paint circlePaint2;
Display(Context context) {
super(context);
}
void init() {
backPaint = new Paint();
backPaint.setColor(Color.WHITE);
backPaint.setStyle(Paint.Style.FILL);
circlePaint = new Paint();
circlePaint.setColor(Color.YELLOW);
circlePaint2 = new Paint();
circlePaint2.setColor(Color.WHITE);
setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getActionMasked()) {
// if (event.getX(event.getActionIndex()) > 100 && event.getX(event.getActionIndex()) < 200) {
touch1_x = (int) event.getX(event.getActionIndex());
touch1_y = (int) event.getY(event.getActionIndex());
// }
System.out.println("touch1_x ===" + touch1_x);
points.add(new Point(touch1_x, touch1_y));
points.add(new Point(touch1_x, touch1_y));
return true;
}
return false;
}
});
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), backPaint);
canvas.drawCircle(touch1_x, touch1_y, 50, circlePaint);
for(Point p: points){
canvas.drawCircle(p.x, p.y, 50, circlePaint);
}
for(Point p: points){
canvas.drawCircle(p.x, p.y, 50,circlePaint2 );
}
invalidate();
}
}
}
relevant question
You could erase canvas before drawing the next circle, using
canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);
import turtle
t=turtle.Turtle()
wn=turtle.Screen()
for count in range(360):
t.fd(3)
t.rt(1)
wn.exitonclick()
I have a customised view for photo annotate, you can use this to do your job.
1: Create a file AnnotationView.java and copy the following code
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
/**
* #author Bob Gao
* http://bobgao.net
*/
public class AnnotationView extends ImageView implements OnTouchListener {
private static final float KEY_STROKE_WIDTH = 4;
private List<Annotation> annotations = new ArrayList<Annotation>();
private Annotation mAnnotation;
private Canvas mCanvas;
private Paint mPaint;
// private Rect mOutRect;
public AnnotationView(Context context) {
super(context);
setOnTouchListener(this);
setDrawingCacheEnabled(true);
setScaleType(ScaleType.FIT_XY);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.mCanvas = canvas;
for (Annotation annotation : annotations) {
mPaint.setColor(annotation.getColor());
switch (annotation.getShape()) {
case Annotation.KEY_SHAPE_CIRCLE:
drawCircle(annotation.getX(), annotation.getY(), annotation.getRadius());
break;
case Annotation.KEY_SHAPE_ARROW:
drawAL((int) annotation.getX(), (int) annotation.getY(), (int) annotation.getRadius(), annotation.getDegree());
break;
case Annotation.KEY_SHAPE_SQUARES:
drawRect((int) annotation.getX(), (int) annotation.getY(), (int) annotation.getRadius());
break;
case Annotation.KEY_SHAPE_TRIANGLE:
drawTriangle((int) annotation.getX(), (int) annotation.getY(), (int) annotation.getRadius(), annotation.getDegree());
break;
}
}
}
/**
* Draw a triangle
*
* #param x
* #param y
* #param r
*/
public void drawTriangle(int x, int y, int r, float degree) {
Path path = new Path();
path.moveTo(x, y);
path.lineTo(x - 2 * r, y + 2 * r);
path.lineTo(x + 2 * r, y + 2 * r);
path.lineTo(x, y);
path.close();
rotatePath(path, degree);
mCanvas.drawPath(path, mPaint);
}
public void drawRect(int x, int y, int r) {
int lenght = 4 * r;
int left = x - lenght / 2;
int top = y - lenght / 2;
int right = x + lenght / 2;
int bottom = y + lenght / 2;
Path path = new Path();
path.moveTo(left, top);
path.lineTo(right, top);
path.lineTo(right, bottom);
path.lineTo(left, bottom);
path.lineTo(left, top);
path.close();
mCanvas.drawPath(path, mPaint);
}
public void drawCircle(float x, float y, float r) {
mCanvas.drawCircle(x, y, r, mPaint);
}
/**
* Draw arrow
*
* #param sx
* #param sy
* #param ex
* #param ey
*/
public void drawAL(int sx, int sy, int r, float degree) {
int ex = (int) (sx + 2 * r);
int ey = (int) (sy + 2 * r);
switch (new Float(degree).intValue()) {
case 90:
ex = (int) (sx - 2 * r);
ey = (int) (sy + 2 * r);
break;
case 180:
ex = (int) (sx - 2 * r);
ey = (int) (sy - 2 * r);
break;
case 270:
ex = (int) (sx + 2 * r);
ey = (int) (sy - 2 * r);
break;
}
double H = 8; // the height of arrow
double L = 3.5; // half of bottom line
int x3 = 0;
int y3 = 0;
int x4 = 0;
int y4 = 0;
double awrad = Math.atan(L / H); // the rotation of arrow
double arraow_len = Math.sqrt(L * L + H * H); // the length of arrow
double[] arrXY_1 = rotateVec(ex - sx, ey - sy, awrad, true, arraow_len);
double[] arrXY_2 = rotateVec(ex - sx, ey - sy, -awrad, true, arraow_len);
double x_3 = ex - arrXY_1[0]; // (x3,y3) the first point
double y_3 = ey - arrXY_1[1];
double x_4 = ex - arrXY_2[0]; // (x4,y4) the second point
double y_4 = ey - arrXY_2[1];
Double X3 = new Double(x_3);
x3 = X3.intValue();
Double Y3 = new Double(y_3);
y3 = Y3.intValue();
Double X4 = new Double(x_4);
x4 = X4.intValue();
Double Y4 = new Double(y_4);
y4 = Y4.intValue();
// draw line
mCanvas.drawLine(sx, sy, ex, ey, mPaint);
Path triangle = new Path();
triangle.moveTo(ex, ey);
triangle.lineTo(x3, y3);
triangle.lineTo(x4, y4);
triangle.close();
mCanvas.drawPath(triangle, mPaint);
}
// Calculate
public double[] rotateVec(int px, int py, double ang, boolean isChLen, double newLen) {
double mathstr[] = new double[2];
// 矢量旋转函数,参数含义分别是x分量、y分量、旋转角、是否改变长度、新长度
double vx = px * Math.cos(ang) - py * Math.sin(ang);
double vy = px * Math.sin(ang) + py * Math.cos(ang);
if (isChLen) {
double d = Math.sqrt(vx * vx + vy * vy);
vx = vx / d * newLen;
vy = vy / d * newLen;
mathstr[0] = vx;
mathstr[1] = vy;
}
return mathstr;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (mAnnotation != null) {
float minX = 0;
float minY = 0;
float maxX = 0;
float maxY = 0;
switch (mAnnotation.getShape()) {
case Annotation.KEY_SHAPE_ARROW:
minX = 0;
minY = 0;
maxX = getLeft() + getWidth() - mAnnotation.getRadius();
maxY = getTop() + getHeight() - mAnnotation.getRadius();
break;
case Annotation.KEY_SHAPE_SQUARES:
minX = getLeft() + mAnnotation.getRadius() / 2;
minY = getTop() + mAnnotation.getRadius() / 2;
maxX = getLeft() + getWidth() - mAnnotation.getRadius() / 2;
maxY = getTop() + getHeight() - mAnnotation.getRadius() / 2;
break;
case Annotation.KEY_SHAPE_CIRCLE:
minX = 0;
minY = 0;
maxX = getLeft() + getWidth() - mAnnotation.getRadius();
maxY = getTop() + getHeight() - mAnnotation.getRadius();
case Annotation.KEY_SHAPE_TRIANGLE:
minX = getLeft() + mAnnotation.getRadius();
minY = getTop() + mAnnotation.getRadius();
maxX = getLeft() + getWidth() - mAnnotation.getRadius();
maxY = getTop() + getHeight() - mAnnotation.getRadius();
break;
}
if (x > minX && x < maxX && y > minY && y < maxY) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mAnnotation.setX(x);
mAnnotation.setY(y);
postInvalidate();
case MotionEvent.ACTION_MOVE:
mAnnotation.setX(x);
mAnnotation.setY(y);
postInvalidate();
break;
}
}
return true;
}
return false;
}
public void startAnnotate(String pathName) {
mAnnotation = new Annotation();
mAnnotation.setMaxRadius(getWidth() / 2);
mAnnotation.setColor(Color.RED);
mAnnotation.setX(getWidth() / 2);
mAnnotation.setY(getHeight() / 2);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(KEY_STROKE_WIDTH);
annotations.add(mAnnotation);
postInvalidate();
}
public void stopAnnotate() {
if (annotations.isEmpty()) {
mPaint = null;
mAnnotation = null;
} else {
annotations.remove(annotations.size() - 1);
if (annotations.isEmpty()) {
mAnnotation = null;
mPaint = null;
} else {
mAnnotation = annotations.get(annotations.size() - 1);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(mAnnotation.getColor());
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(KEY_STROKE_WIDTH);
}
}
postInvalidate();
}
public void plus() {
if (mAnnotation != null) {
mAnnotation.plus();
postInvalidate();
}
}
public void sub() {
if (mAnnotation != null) {
mAnnotation.sub();
postInvalidate();
}
}
public void rotateRight() {
if (mAnnotation != null) {
if (mAnnotation.getDegree() >= 360) {
mAnnotation.setDegree(0);
} else {
mAnnotation.setDegree(mAnnotation.getDegree() + 90);
}
postInvalidate();
}
}
public void rotateLeft() {
if (mAnnotation != null) {
if (mAnnotation.getDegree() <= 0) {
mAnnotation.setDegree(270);
} else {
mAnnotation.setDegree(mAnnotation.getDegree() - 90);
}
postInvalidate();
}
}
public void changeColor(int color) {
if (mAnnotation != null) {
mAnnotation.setColor(color);
mPaint.setColor(color);
}
postInvalidate();
}
/**
* Change the shape
*
* #param id
*/
public void changeShape(int id) {
if (mAnnotation != null) {
mAnnotation.setShape(id);
postInvalidate();
}
}
/**
* Draw line
*
* #param fromX
* start point x
* #param fromY
* start point y
* #param toX
* end point x
* #param toY
* end point y
*/
public void drawLine(float fromX, float fromY, float toX, float toY) {
Path linePath = new Path();
linePath.moveTo(fromX, fromY);
linePath.lineTo(toX, toY);
linePath.close();
mCanvas.drawPath(linePath, mPaint);
invalidate();
}
public List<Annotation> getAnnotations() {
return annotations;
}
private void rotatePath(Path path, float degree) {
Matrix mMatrix = new Matrix();
RectF bounds = new RectF();
path.computeBounds(bounds, true);
mMatrix.postRotate(degree, (bounds.right + bounds.left) / 2, (bounds.bottom + bounds.top) / 2);
path.transform(mMatrix);
}
}
2. In your activity, create the AnnotationView and assign your image to it, then append this view to your root view.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AnnotationView mPreview = (FrameLayout) findViewById(R.id.camera_preview);
AnnotationView mAnnotationView = new AnnotationView(this);
Bitmap bitmap;
try {
bitmap = CBitmapUtil.decode(mPictureFile); // Get your image as a bitmap
mAnnotationView.setImageBitmap(bitmap);
mPreview.addView(mAnnotationView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Photo cannot be saved, please try again later.", Toast.LENGTH_SHORT).show();
}
}

How to resize bitmap in canvas?

I can't find a answer on other questions here and on Google.
The problem is, that the Bitmaps created in GameView are too big on some screens (on my Galaxy S5 they are correct) and they should be scaled with theGameView.getDensity().
GameView class:
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.circle_green);
Circle class:
private int score;
private int y = 0;
private int x = 0;
private int Speed, width, height;
private GameView theGameView;
private Bitmap bmp;
private Random rnd;
public Circle(GameView theGameView, Bitmap bmp) {
this.theGameView = theGameView;
this.bmp = bmp;
this.width = bmp.getWidth();
this.height = bmp.getHeight();
this.score = theGameView.getScore();
rnd = new Random();
x = (int) (30 * theGameView.getDensity() + rnd.nextInt((int) (theGameView.getWidth() - width - 50 * theGameView.getDensity())));
y = (int) (60 * theGameView.getDensity() + rnd.nextInt((int) (theGameView.getHeight() - height - 80 * theGameView.getDensity())));
Speed = (int) (2 * theGameView.getDensity());
}
private void bounceOff() {
if (x + 10 * theGameView.getDensity() > theGameView.getWidth() - width - Speed || x + Speed < 10 * theGameView.getDensity()) {
Speed = -Speed;
}
x = x + Speed;
if (y + 60 * theGameView.getDensity() > theGameView.getHeight() - height - Speed || y + Speed < 60 * theGameView.getDensity()) {
Speed = -Speed;
}
y = y + Speed;
}
public void onDraw(Canvas canvas) {
bounceOff();
if(canvas != null) {
canvas.drawBitmap(bmp, x, y, null);
}
}
public boolean isTouched(float x2, float y2) {
return x2 > x && x2 < x + width && y2 > y && y2 < y + height;
}
It's very easy. Just use canvas.scale
canvas.save(); // Save current canvas params (not only scale)
canvas.scale(scaleX, scaleY);
canvas.restore(); // Restore current canvas params
scale = 1.0f will draw the same visible size bitmap

Graph and zoom function

I would like to add a zooming function in my graph.
For exemple, if the maxY of my graph is 5000, and i zoom a distance of 200 meters around the center, my axis should represent values from 2400 to 2600, the center at being 2500.
private class ZoomHandler implements MouseWheelListener {
public void mouseWheelMoved(MouseWheelEvent e) {
double distanceY = maxY;
double cursorY = maxY / 2.0;
int rotation = e.getWheelRotation();
if (rotation < 0) {
distanceY = 200 / 2;
} else {
distanceY = 200 * 2;
}
maxY = cursorY + distanceY;
repaint();
}
}
Can somebody help with math operation ?
Thank you.
The graph is draw this way:
private void drawAxis(Graphics2D g2) {
FontMetrics metrics = g2.getFontMetrics();
double axisH = yPositionToPixel(originY);
double axisV = xPositionToPixel(originX);
g2.drawLine(0 + V_BORDER, (int) axisH, getWidth(), (int) axisH);
g2.drawLine((int) axisV, (int) axisH, (int) axisV, getHeight() - H_BORDER);
}
protected double yPositionToPixel(double position) {
double height = (double) getHeight();
return pixelOriginY + (position) / (maxY) * (height - (pixelOriginY + H_BORDER));
}
protected double xPositionToPixel(double position) {
double width = getWidth();
return (width) - pixelOriginX - (position - minX) / (maxX - minX) * (width - (pixelOriginX + V_BORDER));
}
private void drawHorizontalLabels(Graphics2D g2) {
double axisV = xPositionToPixel(originX);
FontMetrics metrics = g2.getFontMetrics();
for (double y = originY + majorY; y < maxY + majorY; y += majorY) {
int position = (int) yPositionToPixel(y);
if (rightToLeft) {
g2.drawString(formatter.format(y), (int) axisV + 5, position);
}}
The constructor look like this :
public Graph(double originX, double originY, double pixelOriginX, double pixelOriginY,
double minX, double maxX,
double minY, double maxY,
double majorX, double majorY, String labelXaxis, String labelYaxis) {}
And this is how i initialise it :
new GraphDisplay(0.0, 0.0, 40, 100, -0.1, 120, -0.1, 5000, 20, 1000);
GraphDisplay extends Graph.
JFreeChart has this already built in.

Categories