在画布上绘制箭头,需要的效果如下图:
分解这个图形可以由一个梯形、三角形组成,剩下的就是需要计算三角形、梯形各个顶点的坐标了,这里就是比较麻烦的地方,说白了也是个数学问题,搞懂原理,剩下的就是工作量了。
对图形进行分解,如下图:
r(x,y)点旋转一个角度α,到B(x,y),计算B点的坐标公式:
bx=R*cos(α)+rx;
by=R*sin(α)+ry;
看明白了这个公式,套用到箭头中,就可以简单的算个各个顶点的坐标了,核心代码如下:
/**
* 绘制箭头
*
* @param canvas 画布
* @param sx 起点x
* @param sy 起点y
* @param ex 终点x
* @param ey 终点y
* @param paint 画笔
*/
public static void drawArrow(Canvas canvas, float sx, float sy, float ex, float ey, Paint paint) {
float px = ex - sx; //两点x间距离
float py = ey - sy; //两点y间距离
float arrowSize = paint.getStrokeWidth(); //箭头高度
double H = arrowSize; // 箭头高度 H
double L = arrowSize / 2; // 箭头底边 L 的长度
double awrad = Math.atan(L / 2 / H); // 箭头角度
double arraow_len = Math.sqrt(L / 2 * L / 2 + H * H) - 5; // 箭头所在的斜边长
double[] arrXY_1 = rotateVec(px, py, awrad, true, arraow_len);
double[] arrXY_2 = rotateVec(ex - sx, py, -awrad, true, arraow_len);
float x2 = (float) (ex - arrXY_1[0]); // (x2,y2)是第二端点
float y2 = (float) (ey - arrXY_1[1]);
float x3 = (float) (ex - arrXY_2[0]); // (x3,y3)是第三端点
float y3 = (float) (ey - arrXY_2[1]);
double TL = L / 2; //梯形短边长度
arraow_len = Math.sqrt(px * px + py * py);
awrad = Math.atan(TL / 2 / arraow_len); // 箭头角度
double[] T1 = rotateVec(px, py, awrad, true, arraow_len);
double[] T2 = rotateVec(px, py, -awrad, true, arraow_len);
float tx1 = (float) (ex - T1[0]);
float ty1 = (float) (ey - T1[1]);
float tx2 = (float) (ex - T2[0]);
float ty2 = (float) (ey - T2[1]);
// 画线
Path linePath = new Path();
linePath.moveTo(sx, sy);
linePath.lineTo(tx1, ty1);
linePath.lineTo(x2, y2);
linePath.lineTo(x3, y3);
linePath.lineTo(tx2, ty2);
linePath.close();
canvas.drawPath(linePath, paint);
awrad = Math.atan(L / H); // 箭头角度
arraow_len = Math.sqrt(L * L + H * H); // 箭头的斜边长
arrXY_1 = rotateVec(px, py, awrad, true, arraow_len);
arrXY_2 = rotateVec(px, py, -awrad, true, arraow_len);
x2 = (float) (ex - arrXY_1[0]); // (x2,y2)是第二端点
y2 = (float) (ey - arrXY_1[1]);
x3 = (float) (ex - arrXY_2[0]); // (x3,y3)是第三端点
y3 = (float) (ey - arrXY_2[1]);
Path triangle = new Path();
triangle.moveTo(ex, ey);
triangle.lineTo(x2, y2);
triangle.lineTo(x3, y3);
triangle.close();
canvas.drawPath(triangle, paint);
}
/**
* 计算 向量(px,py) 旋转ang角度后的新长度
*
* @return
*/
public static double[] rotateVec(float px, float 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;
}