【问题标题】:Draw parallel lines along a path - PHP GD沿路径绘制平行线 - PHP GD
【发布时间】:2010-09-29 18:17:43
【问题描述】:

我需要使用 PHP 的图像库来绘制类似地铁地图的东西(沿同一路径的多条路线)。这是一个例子:

********* ******** * ******* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ******************** * ********************* ************************

沿着这条路径画一条线很容易。我不知道如何绘制多条沿着路径但它们之间的空间相等的线。

【问题讨论】:

    标签: php path drawing


    【解决方案1】:

    对于给定的点 A,以及穿过它的更多线,对于第一个点,您必须决定点是进入轨道“内部”(B)还是“外部”(C):

      ********C
      D******A *
      Q*****B * *
             * * *
              * E *
    

    现在,您可以计算点 B 到点 A 的偏移量,作为从长度 = 偏移量(例如 5px)沿角度的路径,即“内部”B 的 AE 和 AD 之间的顺时针角度的一半(或“外部”C 的从 AD 到 AE 的顺时针角度,或者稍后仅使用负偏移)。你会想要 B 点在距离 A 5px 的地方,沿着穿过 A 的线,角度为 angle AE + ((angle AD - angle AE) / 2)

    我绝不是数学奇才,我唯一需要像在 javascript 中那样计算角度的时候,我会举个例子,你可以重写 PHP (任何人 懂数学,如有需要,请随意大笑和纠正):

    var dx = b.x - a.x;
    var dy = b.y - a.y;
    if(dx == 0 && dy == 0){
        answer = 0;
    } else if(dx > 0 && dy >= 0 ){
        answer = Math.atan(dy/dx);
    } else if(dx <= 0 && dy > 0){
        answer = Math.atan(dx/dy) + (Math.PI * 0.5);
    } else if(dx <= 0 && dy <= 0){
        answer = Math.atan(dy/dx) + Math.PI;
    } else if(dx >= 0 && dy <= 0){
        answer = Math.atan(dy/dx) + (Math.PI * 1.5);
    }
    

    所以,在 D=(0,10),A=(10,10), E=(20,20) 的网格中:

    • 通过 AE 的角度 = 45° (PI/4 rad),通过 AD = 180° (PI rad)
    • 那么通过 AB 的角度为 (45 + ((180-45)/2))=> 112.5° (5/8 PI rad)
    • 从 A=(10,10) 到角度 112.5° 的 5px 偏移量为您提供了 B 的位置:
      • Bx = Ax + (cos(angle) * 5) = +/- 8.1
      • By = Ay + (sin(angle) * 5) = +/- 14.6
    • 在起点 D 旁边的“兄弟”点 Q 上,您没有以前的参考路径/计算角度,所以我会取垂直线:角度 DQ = 角度 DA + 90° (PI/ 2 rad)(在示例中你可以只做 Dy+5,但也许你并不总是平行于 2 轴之一开始)
    • 冲洗并重复所有其他点,在计算的坐标之间画线。

    【讨论】:

    • 使用叉积更容易确定点位于哪一侧。以下是示例:stackoverflow.com/questions/3461453/…
    • @LearnCocos2D: 呃.. 这是不久前的事了(将近 2 年),但是:你认为在这个问题中我们需要“确定在哪一边”?我们不是在这里比较这些点,我们实际上是在制作它们......使点“内”/“右”或“外”/“左”是(1)相对于前一行,但更重要的是(2)一开始就做出了一次选择/用户决策,只是使用正(+)或负(-)偏移(在本例中为 5px 或 -5px)的区别。还是我完全错过了什么?
    • 我很欣赏到交叉产品 BTW 的链接,现在正在阅读它,但我真的很难看到它与手头的问题的相关性,这如何帮助计算 B 点的坐标?
    • 我指的是这句话:“对于第一点,你必须决定点是在赛道'内部'(B)还是'外部'©”我认为这就是你的意图做,确定点去哪边。所以我搜索并找到了线路侧帖子。我认为它与所有 atan 计算所做的相同。那部分似乎有点独立,与描述的其余部分分离,我什至不确定它到底做了什么。例如,“answer”变量包含哪些信息?
    • 神奇的词是 decide:OP 想要在已经存在的集合 (A) 旁边绘制一系列平行线/向量。现有集合的坐标是已知的,必须计算新平行集合的坐标。唯一的用户决定是决定路径应该是通过B 还是通过C,剩下的只是计算。 js-match 部分中的answer 是给定2个已知坐标的弧度角,其中坐标的顺序很重要(即从(1,1)(2,2) 的一条线是从(2,2) 到@ 的另一条线987654337@.
    【解决方案2】:

    为了补充 Wrikken 的回答,这里有一个使用 Objective-C 和从这个线程和其他线程重建的 cocos2d-iphone 引擎的实际代码示例。不需要 atan,而是使用叉积,请参阅代码示例末尾的 C 函数和 this link

    我还简单地将偏移向量的符号从 A 切换到 B,以便将向量从 A 获取到 C。这样可以避免调用 cosf/sinf 两次。

    PS:此代码在从i = 0i &lt; numVertices 的for 循环中运行。

    CGPoint splinePoint = splinePoints[i];
    
    CGPoint prevPoint = (i == 0) ? splinePoint : splinePoints[i - 1];
    CGPoint railPoint = splinePoint;
    CGPoint nextPoint = (i == (numVertices-1)) ? splinePoint : splinePoints[i + 1];
    
    CGPoint toPrevPoint = ccpSub(railPoint, prevPoint);
    CGPoint toNextPoint = ccpSub(railPoint, nextPoint);
    float angleToPrevPoint = ccpAngleSigned(kAngleOriginVector, toPrevPoint);
    float angleToNextPoint = ccpAngleSigned(kAngleOriginVector, toNextPoint);
    float offsetAngle = 0.0f;
    
    if (i > 0 && i < (numVertices - 1))
    {
        offsetAngle = angleToNextPoint + ((angleToPrevPoint-angleToNextPoint) / 2);
    }
    else if (i == 0)
    {
        offsetAngle = angleToNextPoint + M_PI_2;
    }
    else
    {
        offsetAngle = angleToPrevPoint + M_PI_2;
    }
    
    CGPoint offsetLeftRail, offsetRightRail, offsetRail;
    offsetRail.x = cosf(offsetAngle) * railOffsetFromCenter;
    offsetRail.y = sinf(offsetAngle) * railOffsetFromCenter;
    offsetLeftRail = ccpAdd(railPoint, offsetRail);
    offsetRightRail = ccpAdd(railPoint, ccpMult(offsetRail, -1.0f));
    
    if (isPointToTheLeftOfLine(prevPoint, railPoint, offsetLeftRail))
    {
        leftRailSplinePoints[i] = offsetLeftRail;
        rightRailSplinePoints[i] = offsetRightRail;
    }
    else
    {
        leftRailSplinePoints[i] = offsetRightRail;
        rightRailSplinePoints[i] = offsetLeftRail;
    }
    
    BOOL isPointToTheLeftOfLine(CGPoint start, CGPoint end, CGPoint test)
    {
        return ((end.x - start.x) * (test.y - start.y) -
                (end.y - start.y) * (test.x - start.x)) > 0;
    }
    

    这有助于我在铁轨上画出铁轨:

    【讨论】:

    • 什么是 railOffsetFromCenter ?
    猜你喜欢
    • 2023-03-05
    • 1970-01-01
    • 2021-09-09
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2011-04-09
    • 2014-04-29
    相关资源
    最近更新 更多