rotation of line in an android canvas - android

i've a math problem, i create a line with each extremety, a perpendicular line but i would like to choose the length of these perpendicular lines but i don't know how to do this :(
this is my code :
int vX = fleche.endPoint.x - fleche.startPoint.x;
int vY = fleche.endPoint.y - fleche.startPoint.y;
int vXP = - ( fleche.endPoint.y - fleche.startPoint.y );
Paint p = new Paint();
p.setColor(fleche.color);
p.setTextSize(30);
p.setTextAlign(Paint.Align.CENTER);
p.setStrokeWidth(8);
p.setAlpha(fleche.alpha);
Path path = new Path();
path.moveTo(fleche.startPoint.x - 10,fleche.startPoint.y - 10);
path.lineTo(fleche.endPoint.x - 10, fleche.endPoint.y - 10);
c.drawTextOnPath(fleche.value + fleche.unit, path, 30, 0, p);
c.drawPath(path, p);
path.moveTo(fleche.startPoint.x - 10,fleche.startPoint.y - 10);
path.lineTo(fleche.endPoint.x - 10, fleche.endPoint.y - 10);
c.drawTextOnPath(fleche.value + fleche.unit, path, 30, 0, p);
//ligne principale
c.drawLine(fleche.startPoint.x, fleche.startPoint.y, fleche.endPoint.x, fleche.endPoint.y, p);
//left
c.drawLine(fleche.startPoint.x, fleche.startPoint.y, fleche.startPoint.x + vXP, fleche.startPoint.y + vX, p);
c.drawLine(fleche.startPoint.x, fleche.startPoint.y, fleche.startPoint.x - vXP, fleche.startPoint.y - vX, p);
//right
c.drawLine(fleche.endPoint.x, fleche.endPoint.y, fleche.endPoint.x + vXP, fleche.endPoint.y + vX, p);
c.drawLine(fleche.endPoint.x, fleche.endPoint.y, fleche.endPoint.x - vXP, fleche.endPoint.y - vX, p);
//Tools.logDebug("Fleche créée(" + i + "/" + (arrows.size()-1) + ") :" + fleche.toString());
Thanks in advance to all :D

This is how you can scale dx and dy to length L:
float ratio = L / Math.sqrt(dx * dx + dy * dy);
dx *= ratio;
dy *= ratio;
edit after comment:
//left
final float L = 20.0f; // for instance
final float ratio = L / Math.sqrt(vXP * vXP + vX * vX);
final float dx = vXP * ratio;
final float dy = vX * ratio;
c.drawLine(fleche.startPoint.x, fleche.startPoint.y, fleche.startPoint.x + dx, fleche.startPoint.y + dy, p);
c.drawLine(fleche.startPoint.x, fleche.startPoint.y, fleche.startPoint.x - dx, fleche.startPoint.y - dy, p);

Related

How to capture detected face image using MLKit firebase FaceDetection

I want to only capture detected face image not whole image on camerasource.
I am drowing box like this
public void draw(Canvas canvas) {
Face face = mFace;
if (face == null) {
return;
}
// Draws a circle at the position of the detected face, with the face's track id below.
float x = translateX(face.getPosition().x + face.getWidth() / 2);
float y = translateY(face.getPosition().y + face.getHeight() / 2);
canvas.drawCircle(x, y, FACE_POSITION_RADIUS, mFacePositionPaint);
canvas.drawText("id: " + mFaceId, x + ID_X_OFFSET, y + ID_Y_OFFSET, mIdPaint);
canvas.drawText("happiness: " + String.format("%.2f", face.getIsSmilingProbability()), x - ID_X_OFFSET, y - ID_Y_OFFSET, mIdPaint);
canvas.drawText("right eye: " + String.format("%.2f", face.getIsRightEyeOpenProbability()), x + ID_X_OFFSET * 2, y + ID_Y_OFFSET * 2, mIdPaint);
canvas.drawText("left eye: " + String.format("%.2f", face.getIsLeftEyeOpenProbability()), x - ID_X_OFFSET*2, y - ID_Y_OFFSET*2, mIdPaint);
// Draws a bounding box around the face.
float xOffset = scaleX(face.getWidth() / 2.0f);
float yOffset = scaleY(face.getHeight() / 2.0f);
float left = x - xOffset;
float top = y - yOffset;
float right = x + xOffset;
float bottom = y + yOffset;
this.faceTrackingCords.y = top;
this.faceTrackingCords.width = right;
this.faceTrackingCords.x = left-right;
this.faceTrackingCords.height = bottom;
canvas.drawRect(left, top, right, bottom, mBoxPaint);
}
and trying to capture image like this but cropped image is not as expected.
mCameraSource.takePicture(null, new CameraSource.PictureCallback() {
#Override
public void onPictureTaken(byte[] bytes) {
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Bitmap bitmapCropped = Bitmap.createBitmap(bitmap,(int)faceTrackingCords.x, (int)faceTrackingCords.y,
(int)faceTrackingCords.width, (int)faceTrackingCords.height);
screenImage.setImageBitmap(bitmapCropped);
}
});
Kindly please help

Fill arrow head goes off in line in canvas Android

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à

Android View Invalidate optimization idea

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.

Android BlurMaskFilter Issues

I'm creating a drawing app, and I want on of the brushes the user can draw with to have the following effect:
Currently, to achieve this effect, I'm drawing 5 separate Paths, each with the same X values but a small Y offset, and each with a BlurMaskFilter. Here's the code from the PaintBrush class:
public PaintBrush(int initColor, int initSize) {
strokeRadius = ((10 * initSize) + 20) / 2;
currentColor = initColor
setupPaths();
}
private void setupPaths(){
paths = new Path[5];
paints = new Paint[5];
for (int i = 0; i < 5; i++){
paths[i] = new Path();
Paint curPaint = new Paint();
curPaint.setColor(currentColor);
curPaint.setAntiAlias(true);
curPaint.setDither(true);
curPaint.setStyle(Paint.Style.STROKE);
curPaint.setStrokeJoin(Paint.Join.ROUND);
curPaint.setStrokeCap(Paint.Cap.ROUND);
paints[i] = curPaint;
}
Paint paint1 = paints[0];
paint1.setStrokeWidth(strokeRadius / 3);
paint1.setMaskFilter(new BlurMaskFilter(Math.max(strokeRadius / 5, 1), BlurMaskFilter.Blur.NORMAL));
Paint paint2 = paints[1];
paint2.setStrokeWidth(strokeRadius / 6);
paint2.setMaskFilter(new BlurMaskFilter(Math.max(strokeRadius / 7, 1), BlurMaskFilter.Blur.NORMAL));
Paint paint3 = paints[2];
paint3.setStrokeWidth(strokeRadius / 5);
paint3.setMaskFilter(new BlurMaskFilter(Math.max(strokeRadius / 7, 1), BlurMaskFilter.Blur.NORMAL));
Paint paint4 = paints[3];
paint4.setStrokeWidth(strokeRadius / 3);
paint4.setMaskFilter(new BlurMaskFilter(Math.max(strokeRadius / 4, 1), BlurMaskFilter.Blur.NORMAL));
Paint paint5 = paints[4];
paint5.setStrokeWidth(strokeRadius / 4);
paint5.setMaskFilter(new BlurMaskFilter(Math.max(strokeRadius / 4, 1), BlurMaskFilter.Blur.NORMAL));
}
public void drawBrush(Canvas canvas){
for (int i = 0; i < 5; i++) {
canvas.drawPath(paths[i], paints[i]);
}
}
public void startStroke(float x, float y){
paths[0].moveTo(x, y - (strokeRadius * 4 / 6));
paths[1].moveTo(x, y - (strokeRadius / 3));
paths[2].moveTo(x, y - (strokeRadius / 8));
paths[3].moveTo(x, y + (strokeRadius / 3));
paths[4].moveTo(x, y + (strokeRadius * 3 / 4));
prevX = x;
prevY = y;
}
public void moveStroke(float x, float y){
float dx = Math.abs(x - prevX);
float dy = Math.abs(y - prevY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
paths[0].quadTo(prevX, prevY - (strokeRadius * 4 / 6), (x + prevX) / 2, ((y + prevY) / 2) - (strokeRadius * 4 / 6));
paths[1].quadTo(prevX, prevY - (strokeRadius / 3), (x + prevX) / 2, ((y + prevY) / 2) - (strokeRadius / 3));
paths[2].quadTo(prevX, prevY - (strokeRadius / 8), (x + prevX) / 2, ((y + prevY) / 2) - (strokeRadius / 8));
paths[3].quadTo(prevX, prevY + (strokeRadius / 3), (x + prevX) / 2, ((y + prevY) / 2) + (strokeRadius / 3));
paths[4].quadTo(prevX, prevY + (strokeRadius * 3 / 4), (x + prevX) / 2, ((y + prevY) / 2) + (strokeRadius * 3 / 4));
}
prevX = x;
prevY = y;
}
public void endStroke(Canvas canvas){
drawBrush(canvas);
paths[0].reset();
paths[1].reset();
paths[2].reset();
paths[3].reset();
paths[4].reset();
}
And the code for the custom View:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(drawingCanvas, 0, 0, canvasPaint);
currentBrush.drawBrush(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!activity.isPaused()) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
currentBrush.startStroke(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
currentBrush.moveStroke(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
currentBrush.endStroke(touchX, touchY, drawingCanvas);
break;
default:
return false;
}
invalidate();
}
return true;
}
I'm aware that BlurMaskFilter is not compatible with hardware accelerations, so in my main activity i have the following code:
drawingView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
This code works, however, with hardware acceleration disabled, my drawing activity took a massive (and unacceptable) performance hit; it draws with a extremely noticeable lag, especially as the paths get longer. My question is: is there a way I could increase the performance, without using hardware acceleration, enough to decrease the lag? If not, is there any way to emulate this same effect in ways that are compatible with hardware acceleration?
Keep a Bitmap of the size of the entire screen.
Keep a list of all points that the finger moved through. Have some minimal threshold for the distance from the previous touch point to the last one. You essentially break the drawing motion into a list of points.
Now, every time the finger moves, find the bounding rectangle of the area that was changed since the last touch event you handled, clear this rectangle, and redraw only the lines on the list that are in this rectangle with your drawPath.
You can try using the RasmView library: github.com/Raed-Mughaus/DrawingVie

Android canvas draw multiple rectangles of equal distance

I have 4 Strings. I'd like to draw a rectangle around each, and have them be equal distance to each other. I have code that "works" but I need 3 spaces for my last rectangle to make the distance equal, and I don't understand why. I am using an LG G Watch R, in case it is relevant.
private void drawDate(Canvas canvas, float centerX, float centerY)
{
float x = centerX + 75f;
float y = centerY + 50f;
String dayOfWeek = daysOfWeek[mTime.weekDay] + ",";
String month = months[mTime.month];
String monthDay = mTime.monthDay + ",";
String year = Integer.toString(mTime.year);
float height = outLinePaint.getTextSize();
float totalWidth = outLinePaint.measureText(String.format("%s %s %s %s", dayOfWeek, month, monthDay, year));
final float spaceWidth = outLinePaint.measureText(" ");
x -= totalWidth/2f;
outLinePaint.setStyle(Paint.Style.FILL);
float halfWidth = outLinePaint.measureText(dayOfWeek)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(dayOfWeek, x, y, outLinePaint);
x += (halfWidth*2f)+spaceWidth;
halfWidth = outLinePaint.measureText(month)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(month, x, y, outLinePaint);
x += (halfWidth*2f)+spaceWidth;
halfWidth = outLinePaint.measureText(monthDay)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(monthDay, x, y, outLinePaint);
//THIS LINE
x += (halfWidth*2f)+spaceWidth+spaceWidth+spaceWidth;
//it looks right on the canvas, but why can I not simply
//x += (halfWidth*2f)+spaceWidth; like above?
halfWidth = outLinePaint.measureText(year)/2f;
canvas.drawRect(x - halfWidth, y - height, x + halfWidth, y + height /2f , whitePaint);
canvas.drawText(year, x, y, outLinePaint);
outLinePaint.setStyle(Paint.Style.STROKE);
}
NOTE: THIS "BUG" ONLY EFFECTS THE LAST STRING
This is what I expect (AND what I get if I use x += (halfWidth*2f)+spaceWidth+spaceWidth+spaceWidth;):
However if I use x += (halfWidth*2f)+spaceWidth; like I do with my other 3, I get:
I have solved it. I could not get #pskink's example to work for the life of me (it didn't draw on my canvas). The problem was my center alignment.
x was in the middle of my Rect not the left. Whereas I was expecting x to be the leftmost point in my Rect when I added its width to x.
I have fixed it by setting the text align to left (so that x IS my leftmost point), and changing my drawDate() method to:
float spaceWidth;
private void drawDate(float centerX, float centerY)
{
float x = centerX + centerX*DATE_AND_COMPASS_X_OFFSET;
float y = centerY + centerY*DATE_AND_COMPASS_Y_OFFSET;
String dayOfWeek = daysOfWeek[mTime.weekDay] + ",";
String month = months[mTime.month];
String monthDay = mTime.monthDay + ",";
String year = Integer.toString(mTime.year);
float height = outLinePaint.getTextSize();
float totalWidth = outLinePaint.measureText(String.format("%s %s %s %s", dayOfWeek, monthnthDay, year));
spaceWidth = outLinePaint.measureText(" ");
outLinePaint.setStyle(Paint.Style.FILL);
x-=totalWidth/2;
x+=drawDateInline(dayOfWeek, x, y, height);
x+=drawDateInline(month, x, y, height);
x+=drawDateInline(monthDay, x, y, height);
drawDateInline(year, x, y, height);
outLinePaint.setStyle(Paint.Style.STROKE);
}
private float drawDateInline(String word, float x, float y, float height) {
float width = outLinePaint.measureText(word);
canvas.drawRect(x, y - height, x + width, y + height /2f, whitePaint);
canvas.drawText(word, x, y, outLinePaint);
return width+spaceWidth;
}
I'm also not sure how this is a "bad approach".

Categories

Resources