Нарисуйте параллельные линии вдоль пути - PHP GD - PullRequest
3 голосов
/ 29 сентября 2010

Мне нужно нарисовать что-то вроде карты метро (несколько маршрутов по одному и тому же пути), используя библиотеку изображений PHP.Вот пример:

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

Достаточно просто нарисовать одну линию по этому пути.Я не знаю, как нарисовать несколько линий, которые следуют по пути, но имеют одинаковое расстояние между ними.

Ответы [ 2 ]

2 голосов
/ 30 сентября 2010

Для заданной точки A и нескольких линий, проходящих через нее, для первых точек вам необходимо решить, будут ли точки идти «внутри» (B) дорожки или «снаружи» (C):

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

Теперь вы можете вычислить смещение вашей точки B к точке A как путь с длиной = смещение (например, 5 пикселей) вдоль угла, равного половине угла по часовой стрелке между AE и AD для «внутреннего».B (или угол по часовой стрелке от AD к AE для «внешнего» C, или просто позже используйте отрицательное смещение).Вам понадобится точка B на расстоянии 5px от A вдоль линии, проходящей через 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 рад) , через AD = 180 ° (PI рад)
  • Тогда угол через AB составляет (45 + ((180-45)/2)) => 112,5 ° (5/ 8 PI рад)
  • 5px смещение от A = (10,10) до угла 112,5 ° дает вам это местоположение для B:
    • Bx = Ax + (cos(angle) * 5) = +/- 8.1
    • By = Ay + (sin(angle) * 5) = +/- 14.6
  • В «братской» точке Q рядом с начальной точкой D у вас нет предыдущего пути для привязки / расчета угла, поэтому я бы взял перпендикуляр: угол DQ= угол DA + 90 ° (PI / 2 рад) (в примере вы можете простосделайте Dy + 5, но, возможно, вы не всегда начинаете параллельно одной из двух осей)
  • Промойте и повторите все остальные точки, проведите линии между вычисленными координатами.
0 голосов
/ 15 июля 2012

В дополнение к ответу Вриккена приведен пример кода с использованием Objective-C и движка cocos2d-iphone, восстановленных из этого потока и других.Атан не нужен, вместо этого используется перекрестный продукт, см. Функцию C в конце примера кода и эту ссылку .

Я также просто переключил знак вектора смещения с A на B, чтобы получить вектор от A до C. Это позволяет избежать вызова cosf / sinf дважды.

PS: Этот код выполняетсяв цикле for от i = 0 до i < numVertices.

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;
}

Это помогло мне нарисовать рельсы на рельсовом пути:

enter image description here

...