Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何根据箭头计算箭头的坐标?_Algorithm - Fatal编程技术网

Algorithm 如何根据箭头计算箭头的坐标?

Algorithm 如何根据箭头计算箭头的坐标?,algorithm,Algorithm,我有一条基于两个(x,y)坐标的直线。这条线有起点和终点。现在,我想在直线的端点添加一个箭头 我知道箭头是一个等边三角形,因此每个角度有60度。另外,我知道一侧的长度是20。我也没有三角形的一条边(即直线的终点) 如何计算三角形的其他两点?我知道我应该用一些三角学,但是怎么用呢 另外,直线的端点应该是箭头的尖端。您可以找到直线的角度 Vector ox = Vector(1,0); Vector line_direction = Vector(line_begin.x - line_end.x,

我有一条基于两个(x,y)坐标的直线。这条线有起点和终点。现在,我想在直线的端点添加一个箭头

我知道箭头是一个等边三角形,因此每个角度有60度。另外,我知道一侧的长度是20。我也没有三角形的一条边(即直线的终点)

如何计算三角形的其他两点?我知道我应该用一些三角学,但是怎么用呢


另外,直线的端点应该是箭头的尖端。

您可以找到直线的角度

Vector ox = Vector(1,0);
Vector line_direction = Vector(line_begin.x - line_end.x, line_begin.y - line_end.y);
line_direction.normalize();
float angle = acos(ox.x * line_direction.x + line_direction.y * ox.y);
然后使用此功能,使用找到的角度对所有3个点进行调整

Point rotate(Point point, float angle)
{
    Point rotated_point;
    rotated_point.x = point.x * cos(angle) - point.y * sin(angle);
    rotated_point.y = point.x * sin(angle) + point.y * cos(angle);
    return rotated_point;
}
假设箭头的上端是直线的端点,它将完全旋转并适合直线。 没有测试它=(

让我们看看你的线路是
(x0,y0)-(x1,y1)

反向矢量
(dx,dy)=(x0-x1,y0-y1)

它是norm
norm=Sqrt(dx*dx+dy*dy)

规范化它:
(udx,udy)=(dx/Norm,dy/Norm)

按角度旋转
Pi/6
-Pi/6

ax = udx * Sqrt(3)/2 - udy * 1/2

ay = udx * 1/2 + udy * Sqrt(3)/2

bx = udx * Sqrt(3)/2 + udy * 1/2

by =  - udx * 1/2 + udy * Sqrt(3)/2
你的观点:
(x1+20*ax,y1+20*ay)
(x1+20*bx,y1+20*by)

下面是一个示例程序,演示了如何做到这一点:

void Main()
{
    const int imageWidth = 512;
    Bitmap b = new Bitmap(imageWidth , imageWidth , PixelFormat.Format24bppRgb);

    Random r = new Random();
    for (int index = 0; index < 10; index++)
    {
        Point fromPoint = new Point(0, 0);
        Point toPoint = new Point(0, 0);

        // Ensure we actually have a line
        while (fromPoint == toPoint)
        {
            fromPoint = new Point(r.Next(imageWidth ), r.Next(imageWidth ));
            toPoint = new Point(r.Next(imageWidth ), r.Next(imageWidth ));
        }

        // dx,dy = arrow line vector
        var dx = toPoint.X - fromPoint.X;
        var dy = toPoint.Y - fromPoint.Y;

        // normalize
        var length = Math.Sqrt(dx * dx + dy * dy);
        var unitDx = dx / length;
        var unitDy = dy / length;

        // increase this to get a larger arrow head
        const int arrowHeadBoxSize = 10;

        var arrowPoint1 = new Point(
            Convert.ToInt32(toPoint.X - unitDx * arrowHeadBoxSize - unitDy * arrowHeadBoxSize),
            Convert.ToInt32(toPoint.Y - unitDy * arrowHeadBoxSize + unitDx * arrowHeadBoxSize));
        var arrowPoint2 = new Point(
            Convert.ToInt32(toPoint.X - unitDx * arrowHeadBoxSize + unitDy * arrowHeadBoxSize),
            Convert.ToInt32(toPoint.Y - unitDy * arrowHeadBoxSize - unitDx * arrowHeadBoxSize));

        using (Graphics g = Graphics.FromImage(b))
        {
            if (index == 0)
                g.Clear(Color.White);

            g.DrawLine(Pens.Black, fromPoint, toPoint);
            g.DrawLine(Pens.Black, toPoint, arrowPoint1);
            g.DrawLine(Pens.Black, toPoint, arrowPoint2);
        }
    }

    using (var stream = new MemoryStream())
    {
        b.Save(stream, ImageFormat.Png);
        Util.Image(stream.ToArray()).Dump();
    }
}
void Main()
{
常量int imageWidth=512;
位图b=新位图(imageWidth、imageWidth、PixelFormat.Format24bppRgb);
随机r=新随机();
对于(int-index=0;index<10;index++)
{
点fromPoint=新点(0,0);
点拓扑点=新点(0,0);
//确保我们有一条线路
while(fromPoint==toPoint)
{
fromPoint=新点(r.Next(图像宽度),r.Next(图像宽度));
toPoint=新点(r.Next(图像宽度),r.Next(图像宽度));
}
//dx,dy=箭头线矢量
var dx=toPoint.X-fromPoint.X;
var dy=toPoint.Y—fromPoint.Y;
//正常化
变量长度=数学Sqrt(dx*dx+dy*dy);
var unitDx=dx/长度;
var unitDy=dy/长度;
//增加此值可获得更大的箭头
常数int arrowHeadBoxSize=10;
var ARROWSPOINT1=新点(
将.ToInt32(拓扑点X-unitDx*箭头头框大小-unitDy*箭头头框大小),
将.ToInt32(拓扑点Y-unitDy*箭头箱尺寸+unitDx*箭头箱尺寸));
var ARROWSPOINT2=新点(
将.ToInt32(拓扑点X-unitDx*箭头头框大小+unitDy*箭头头框大小),
将.ToInt32(拓扑点Y-unitDy*箭头头框大小-unitDx*箭头头框大小));
使用(Graphics g=Graphics.FromImage(b))
{
如果(索引==0)
g、 清晰(颜色:白色);
g、 抽绳(黑色、起点、终点);
g、 抽绳(钢笔、黑色、拓朴点、箭头点1);
g、 抽绳(钢笔、黑色、圆点、箭头点2);
}
}
使用(var stream=new MemoryStream())
{
b、 保存(流,ImageFormat.Png);
Util.Image(stream.ToArray()).Dump();
}
}
基本上,你:

  • 计算箭头线的矢量
  • 规范化向量,即使其长度为1
  • 通过以下步骤计算箭头的端点:
  • 首先从头部向后退一定距离
  • 然后从直线垂直出一定距离
  • 请注意,如果希望箭头线的角度不同于45度,则必须使用不同的方法

    上面的程序每次将绘制10个随机箭头,下面是一个示例:


    你不需要三角,只需要一些向量运算

    假设直线从A到B,箭头的前顶点位于B。箭头的长度为h=10(√3) 它的半宽度是w=10。我们将把从A到B的单位向量表示为U=(B-A)/| B-A |(即差值除以差值的长度),垂直于此的单位向量表示为V=[-Uy,Ux]

    根据这些数量,可以将箭头的两个后顶点计算为B-hU±wV

    在C++中:

    struct vec { float x, y; /* … */ };
    
    void arrowhead(vec A, vec B, vec& v1, vec& v2) {
        float h = 10*sqrtf(3), w = 10;
        vec U = (B - A)/(B - A).length();
        vec V = vec(-U.y, U.x);
        v1 = B - h*U + w*V;
        v2 = B - h*U - w*V;
    }
    

    如果要指定不同的角度,则需要一些触发器来计算
    h
    w
    的不同值。假设需要长度为h且尖端角度为θ的箭头,则w=htan(θ/2).然而,在实践中,直接指定
    h
    w
    是最简单的。

    我想根据Marcelo Cantos的答案给出我的答案,因为该算法非常有效。我编写了一个程序来计算投射到CCD阵列上的激光束的质心。找到质心后,方向角为e被画出来,我需要箭头指向那个方向。因为角度是经过计算的,所以箭头必须沿着任何方向的角度

    此代码为您提供了更改箭头大小的灵活性,如图所示

    首先,需要向量结构和所有必需的运算符重载

    private struct vec
    {
        public float x;
        public float y;
    
        public vec(float x, float y)
        {
            this.x = x;
            this.y = y;
        }
    
        public static vec operator -(vec v1, vec v2)
        {
            return new vec(v1.x - v2.x, v1.y - v2.y);
        }
    
        public static vec operator +(vec v1, vec v2)
        {
            return new vec(v1.x + v2.x, v1.y + v2.y);
        }
    
        public static vec operator /(vec v1, float number)
        {
            return new vec(v1.x / number, v1.y / number);
        }
    
        public static vec operator *(vec v1, float number)
        {
            return new vec(v1.x * number, v1.y * number);
        }
    
        public static vec operator *(float number, vec v1)
        {
            return new vec(v1.x * number, v1.y * number);
        }
    
        public float length()
        {
            double distance;
            distance = (this.x * this.x) + (this.y * this.y);
            return (float)Math.Sqrt(distance);
        }
    }
    
    然后,您可以使用Marcelo Cantos给出的相同代码,但我对箭头变量的长度和半宽度进行了调整,以便您在调用函数时可以对其进行定义

    private void arrowhead(float length, float half_width, 
                           vec A, vec B, ref vec v1, ref vec v2)
    {
        float h = length * (float)Math.Sqrt(3);
        float w = half_width;
        vec U = (B - A) / (B - A).length();
        vec V = new vec(-U.y, U.x);
        v1 = B - h * U + w * V;
        v2 = B - h * U - w * V;
    
    }
    
    现在您可以这样调用函数:

    vec leftArrowHead = new vec();
    vec rightArrowHead = new vec();
    arrowhead(20, 10, new vec(circle_center_x, circle_center_y), 
        new vec(x_centroid_pixel, y_centroid_pixel),
        ref leftArrowHead, ref rightArrowHead);
    
    var A = new Vector(start.x,start.y);
    var B = new Vector(end.x,end.y);    
    var vec = getArrowhead(A,B);
    
    console.log(vec[0]);
    console.log(vec[1]);
    
    在我的代码中,圆心是第一个矢量位置(箭头对接),质心_像素是第二个矢量位置(箭头)

    我通过在System.Drawings中的points for graphics.DrawPolygon()函数中存储矢量值来绘制箭头。代码如下所示:

    Point[] ppts = new Point[3];
    ppts[0] = new Point((int)leftArrowHead.x, (int)leftArrowHead.y);
    ppts[1] = new Point(x_cm_pixel,y_cm_pixel);
    ppts[2] = new Point((int)rightArrowHead.x, (int)rightArrowHead.y);
    
    g2.DrawPolygon(p, ppts);
    

    对于任何感兴趣的人,TomP都在想一个JS版本,所以这里是我制作的一个JavaScript版本。它是基于@ PATRATACUS和马塞洛CANTOS的答案。JavaScript不支持操作符重载,所以它不像C++或其他语言那样干净。

    var getArrowhead = function(A, B)
    {
        var h = 10 * Math.sqrt(3);
        var w = 5;
        var v1 = B.subtract(A);
        var length = v1.length();
        var U = v1.divide(length);
        var V = new Vector(-U.y, U.x);
        var r1 = B.subtract(U.multiply(h)).add(V.multiply(w));
        var r2 = B.subtract(U.multiply(h)).subtract(V.multiply(w));
    
        return [r1,r2];
    }
    
    var A = new Vector(start.x,start.y);
    var B = new Vector(end.x,end.y);    
    var vec = getArrowhead(A,B);
    
    console.log(vec[0]);
    console.log(vec[1]);