Canvas绘制箭头

在画布上绘制箭头,需要的效果如下图:
在这里插入图片描述
分解这个图形可以由一个梯形、三角形组成,剩下的就是需要计算三角形、梯形各个顶点的坐标了,这里就是比较麻烦的地方,说白了也是个数学问题,搞懂原理,剩下的就是工作量了。
对图形进行分解,如下图:
在这里插入图片描述
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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值