Canvas画箭头

3,903 阅读3分钟

问题描述

带箭头的线段

在平面直角坐标系里,给定任意两点A(x1,y1)、B(x2,y2),画一条带箭头的线段,箭头是个等腰三角形,由B、C、D三个点组成,CD作为箭头的底边垂直于线段AB, 现在已知箭头的底边长度的一半是w,箭头的高度是h,箭头与线段AB的两个夹角都是θ,求C和D点的坐标?

解法一

构建相似三角形求解

数学解法

画坐标轴平行线,并利用延长线构建相似三角形求解!!!

相似三角形解法
【解】
如上图所示:

1. 作图:
设点P(x,y)为AB和CD的交点,
过A点作x轴的平行线AH,
过B点作y轴的平行线BM, 交AH于M点,
过C点作y轴的平行线CE,
过F点作y轴的平行线DF,交AH于N点,
过P点作x轴的平行线EF,交直线CE于E,交直线DF于F,

由图可知: CE⊥EF, DF⊥EF,BM⊥AH,FN⊥AH

2. 由题意计算: 
   AM长度dx=x2-x1("dx∈R")
   BM长度dy=y2-y1("dx∈R")
   AB长度设为l, 则l^2=dx^2+dy^2

3. 根据相似三角的定义可得以下几组相似三角形:
   △BPF~△BAM
   △CEP~△DFP
   △DFP~△DNH -> △DFP~△APH -> △DFP~△AMB
   △CEP~△AMB
   
4. 由△BPF~△BAM可得:
   PB/AB=BG/BM=PG/AM
   即:
   l/h=BG/dy=PG/dx
   所以:
   BG=l/h*dy
   PG=l/h*dx
   所以P点的坐标: 
   (x,y)=(x2-PG,y2-BG)=(x2-l/h*dx, y2-l/h*dy)
   
5. 由△DFP~△AMB可得:
   DP/AB=DF/AM=PF/BM
   即:
   w/l=DF/dx=PF/dy
   所以:
   DF=w/l*dx
   PF=w/l*dy
   所以D点的坐标为:
   (x+PF,y-DF)=(x+w/l*dy,y-w/l*dx)

6. 由△CEP~△AMB,与⑤同理:
   CP/AB=CE/AM=PE/BM
   即:
   w/l=CE/dx=PE/dy
   所以:
   CE=w/l*dx
   PE=w/l*dy
   所以C点的坐标为:
   (x-PE,y+CE)=(x-w/l*dy,y-w/l*dx)

所以三角箭头的三个坐标点为:
B(x2,y2)
C(x-w/l*dy,y-w/l*dx)=((x2-l/h*dx)-w/l*dy,(y2-l/h*dy)-w/l*dx)
D(x+w/l*dy,y-w/l*dx)=((x2-l/h*dx)+w/l*dy,(y2-l/h*dy)-w/l*dx)

代码实现

  • Android中Canvas绘制代码:
/**
 * 画带箭头的线段:构建相似三角形求解
 * 起点和终点都可以有箭头
 */
private void drawArrowLine2(Canvas canvas, float x1, float y1, float x2, float y2) {
    float h = 18 * 8; // 箭头的高度
    float w = (float) (13.5 * 8); // 箭头底边的一半

    //线段首位端点部分的(△x,△y)横纵坐标差
    float dx = x2 - x1;
    float dy = y2 - y1;
    //线段的长度
    float d = (float) Math.sqrt(dx * dx + dy * dy);

    //(x,y)->(px,py)箭头底边和线段的交点
    float px = x2 - (h / d * dx); //(px ∈ R实数)
    float py = y2 - (h / d * dy); //(py ∈ R)
    
    //为防止线段末尾比箭头突出,此处线段的末尾端点坐标重新计算,末端坐标=箭头底边到箭头的一半位置
    float lineEndX = (px + x2) / 2;
    float lineEndY = (py + y2) / 2;
    canvas.drawLine(x1, y1, lineEndX, lineEndY,paint);
    
    //在终点画箭头
    Path path = new Path();
    path.moveTo(x2, y2);
    //利用相似三角形求出箭头另外两个点的坐标
    path.lineTo(px + (w / d * dy), py - (w / d * dx));
    path.lineTo(px - (w / d * dy), py + (w / d * dx));
    path.close();
    canvas.drawPath(path, arrowPaint);

    //在起点画箭头
    //(x,y)->(topPx,topPy)箭头底边和线段的交点
    /*
    float startPx = x1 + (h / d * dx);
    float startPy = y1 + (h / d * dy);
    
    float lineStartX = (startPx + x1) / 2;
    float lineStartY = (startPy + y1) / 2;
    canvas.drawLine(lineStartX, lineStartY, lineEndX, lineEndY,paint);
    
    Path startPath = new Path();
    startPath.moveTo(x1, y1);
    startPath.lineTo(startPx + (w / d * dy), startPy - (w / d * dx));
    topPath.lineTo(startPx - (w / d * dy), startPy + (w / d * dx));
    startPath.close();
    canvas.drawPath(startPath, arrowPaint);
    */
}