Draw arrow head in canvas using Angle

送分小仙女□ 提交于 2020-05-17 03:53:05

问题


I tried with following code, But this code is not working as expected. Actually I hesitated to ask help for this simple solution, But I have wasted lots of time, finally I came here.

deltaX = bounds.right - bounds.left;
deltaY = bounds.bottom - bounds.top;

double distance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
float arrowLength= (float) (distance / 3);
float lineAngle = (float) Math.atan2(deltaY, deltaX);
float angle = (float) Math.toRadians(20);
float sinValue = (float) Math.sin(lineAngle - angle);
point_x_1 = bounds.left - 20 * sinValue;
point_y_1 = (float) (bounds.bottom - 0.5 * arrowLength* Math.cos(lineAngle - angle));
angle = (float) Math.toRadians(60);
sinValue = (float) Math.sin(lineAngle + angle);
point_x_3 = bounds.left + 20 * sinValue;
point_y_3 = (float) (bounds.bottom + arrowLength* Math.cos(lineAngle + angle));

path.moveTo(bounds.right, bounds.top);
path.lineTo(bounds.left, bounds.bottom);
path.moveTo(point_x_1, point_y_1);
path.lineTo(bounds.left, bounds.bottom);
path.lineTo(point_x_3, point_y_3);

Note: I have four directions, each will come in different scenarios.

enum PathDirection {
    TopLeftToBottomRight,
    TopRightToBottomLeft,
    BottomLeftToTopRight,
    BottomRightToTopLeft
} 

Above code I tried for TopRightToBottomLeft.

Sample Outputs

Pic 1: RectF values: [180.0,560.0][820.0,740.0]

Pic 2: RectF values: [240.0,480.0][640.0,980.0]

Update

path.reset();
canvas.save();
canvas.translate(200, 200);
float direction = (float) Math.atan2(400 - 200, 400 - 200);
canvas.rotate(direction);
path.moveTo(0, 0);
float distance = (float) Math.sqrt(200 * 200 + 200 * 200);
path.lineTo(distance, 0);
float x1 = distance - (distance * 20 / 100);
float y1 = -(distance * 15 / 100);
path.moveTo(x1, y1);
path.lineTo(distance, 0);
x1 = distance - (distance * 20 / 100);
y1 = (distance * 15 / 100);
path.lineTo(x1, y1);
canvas.drawPath(path, mPaint);
canvas.restore();

I used this code to draw line from from position 200, 200 to 300, 300. But this draw the line from 0, 0 to distance.

Screenshot


回答1:


See the javascript code below, that should translate nicely to Java

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");

function drawLine(p1, p2, asize) {
  ctx.beginPath()
  ctx.moveTo(p1.x, p1.y);
  ctx.lineTo(p2.x, p2.y);
  
  if (asize > 0) {
    lineAngle = Math.atan2(p1.y - p2.y, p1.x - p2.x);
    delta = Math.PI/6  
    for (i=0; i<2; i++) {
      ctx.moveTo(p2.x, p2.y);
      x = p2.x + asize * Math.cos(lineAngle + delta)
      y = p2.y + asize * Math.sin(lineAngle + delta)
      ctx.lineTo(x, y);
      delta *= -1
    }
  }
  ctx.stroke();
}

drawLine({x:10, y:10}, {x:100, y:20}, 20)
drawLine({x:20, y:15}, {x:140, y:120}, 20)
drawLine({x:140, y:20}, {x:80, y:50} , 20)

drawLine({x:150, y:20}, {x:150, y:90}, 20)
drawLine({x:180, y:90}, {x:180, y:20}, 20)

drawLine({x:200, y:10}, {x:200, y:140}, 10)
drawLine({x:220, y:140}, {x:220, y:10}, 10)
<canvas id="canvas">

If you run it you should see a few samples.
So let's break it down the drawLine has 3 parameters (p1, p2, asize) the first two are the starting-point and end-point of the line, the last one is arrow size, just to give some control to the final user over how big are those arrows at the end.

You had most of the math in your code but it was a bit mixed up, you did calculate the lineAngle but I got lost in the order of your operations, so better start from scratch.




回答2:


With help from pskink I came to the solution, Sample code, which draw the line with arrow head from 200, 200 to 400, 400

path.reset();
RectF rectF = new RectF(200, 200, 400, 400);
canvas.save();
canvas.translate(rectF.left, rectF.top);
float direction = (float) Math.atan2(rectF.bottom - rectF.top, rectF.right - rectF.left);
float degree = (float) Math.toDegrees(direction);
canvas.rotate(degree);
canvas.drawColor(Color.parseColor("#E3F2FD"));
path.moveTo(0, 0);
float x = rectF.right - rectF.left;
float y = rectF.bottom - rectF.top;
float distance = (float) Math.sqrt(x * x + y * y);
path.lineTo(distance, 0);
float x1 = distance - (distance * 20 / 100);
float y1 = -(distance * 15 / 100);
path.moveTo(x1, y1);
path.lineTo(distance, 0);
float x2 = distance - (distance * 20 / 100);
float y2 = (distance * 15 / 100);
path.lineTo(x2, y2);
canvas.drawPath(path, mPaint);
canvas.restore();

SC:

Note If you don't want to rotate canvas, you can use Helder Sepulveda's answer, it also works as expected.



来源:https://stackoverflow.com/questions/60671113/draw-arrow-head-in-canvas-using-angle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!