Reputation: 2088
The following question might sound a bit stupid but I guess stupidity has no limit so here it goes. I am drawing a Heart using Canvas in Android and have got no issues in drawing the heart but I am not able to make the heart sharp in the meeting point. My heart looks like
CODE :
left_x_moveto = 200;
left_y_moveto = 45;
left_x1 = 197;
left_y1 = -35;
left_x2 = 60;
left_y2 = 20;
left_x3 = 193;
left_y3 = 130;
right_x_moveto = 200;
right_y_moveto = 45;
right_x1 = 197;
right_y1 = -35;
right_x2 = 345;
right_y2 = 20;
right_x3 = 193;
right_y3 = 130;
heart_outline_paint.setColor(getResources().getColor(R.color.heart_outline_color)); // Change the boundary color
heart_outline_paint.setStrokeWidth(15);
heart_outline_paint.setStyle(Paint.Style.STROKE);
path.moveTo(left_x_moveto, left_y_moveto);
path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3);
path.moveTo(right_x_moveto, right_y_moveto);
path.cubicTo(right_x1, right_y1, right_x2, right_y2, right_x3, right_y3);
canvas.drawPath(path, heart_outline_paint);
What have I tried so far :
left_x_moveto
,left_y_moveto
and vice versa but the heart is completely disfigured for which I am unable to find the reason. When the right_x_moveto = 198
and right_y_moveto = 45
, the heart looks like
I am not sure why this is happening.
heart_outline_paint
would give me what I want but I want the thickness of the heart to be the same so reducing the setStrokeWidth
is not an option.In short, I want both the curves to MEET AND MERGE and not just MEET. Any help will be much appreciated. Thanks in advance.
Upvotes: 4
Views: 2655
Reputation: 17851
You need to perform a couple of this.
path.close()
.heart_outline_paint.setStrokeJoin(Paint.Join.MITER);
A path
can be closed only if it's drawn continuously. Hence I have modified the code so that path.close()
can be done properly. Below is the code.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
heart_outline_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
heart_outline_paint.setStrokeJoin(Paint.Join.MITER);
path = new Path();
int left_x_moveto = 200;
int left_y_moveto = 45;
int left_x1 = 180;
int left_y1 = -20;
int left_x2 = 30;
int left_y2 = 20;
int left_x3 = 193;
int left_y3 = 130;
int right_x_moveto = 200;
int right_y_moveto = 45;
int right_x1 = 214;
int right_y1 = -20;
int right_x2 = 375;
int right_y2 = 20;
int right_x3 = 193;
int right_y3 = 130;
heart_outline_paint.setColor(Color.RED); // Change the boundary color
heart_outline_paint.setStrokeWidth(15);
heart_outline_paint.setStyle(Paint.Style.STROKE);
path.moveTo(left_x_moveto, left_y_moveto);
path.cubicTo(left_x1, left_y1, left_x2, left_y2, left_x3, left_y3);
path.cubicTo(right_x2, right_y2, right_x1, right_y1, right_x_moveto, right_y_moveto);
path.close();
canvas.drawPath(path, heart_outline_paint);
}
Paint.Join.MITER
is the one that does what you want.
The outer edges of a join meet at a sharp angle
Now this MITER
join works only when the angle is <= 90 degree. But here, based on the values that you have provided, the angle is 90 degree and hence the MITER
join doesn't work. I have modified the values to get the following image. The image is not exact, but you need to play around with the value the get the right one.
You could set the ROUND
join method to get the following.
The problem is with Path.cubicTo()
. It's very hard to get the MITTER
join work without getting the heart shape squished. So instead of cubicTo
, I tried with lineTo
and arcTo
to create a simple heart. The below is the code for that. You will notice that I have rotated the canvas to 45 degrees and then drew the heart shape. This is purely for convenience, so that the coordinates are simple and does not involve pythagoras theorem.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
heart_outline_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
heart_outline_paint.setStrokeJoin(Paint.Join.MITER);
heart_outline_paint.setColor(Color.RED); // Change the boundary color
heart_outline_paint.setStrokeWidth(15);
heart_outline_paint.setStyle(Paint.Style.STROKE);
path = new Path();
float length = 100;
float x = canvas.getWidth()/2;
float y = canvas.getHeight()/2;
canvas.rotate(45,x,y);
path.moveTo(x,y);
path.lineTo(x-length, y);
path.arcTo(new RectF(x-length-(length/2),y-length,x-(length/2),y),90,180);
path.arcTo(new RectF(x-length,y-length-(length/2),x,y-(length/2)),180,180);
path.lineTo(x,y);
path.close();
canvas.drawPath(path, heart_outline_paint);
}
The final rendered image of this code is below:
Upvotes: 6
Reputation: 2365
What's happening is that the thickness of the line is being drawn on one side, not on both. In true MS paint fashion:
(The left is what's happening, the right is what you want. Black is the actual position of the line would width be 1px, red is the "padding", the 2nd, 3rd through 15th pixel, heart_outline_paint.setStrokeWidth(15);
)
To fix this, try to subtract half the width of the line from the x of right line, and add it to the x of the left line. Doing so will work around this problem, not fix it
Upvotes: 0