1

I'm using imagefilledpolygon to draw an arrow on a GIF image (PHP) and I'd like to make the arrowhead outlined in black. I first create a triangle for the arrow and then draw a thick line at the base of the triangle for the arrow effect.

One solution I think is to create two triangle arrows, the first one being black and slightly larger than the first (to create an outline effect) but I'm not sure how to go about the math of that.

Any help would be great!

Code to create the arrow (head and tail):

function arrow($img, $x1, $y1, $x2, $y2, $alength, $awidth, $color) {
    $distance = sqrt(pow($x1 - $x2, 2) + pow($y1 - $y2, 2));

    $dx = $x2 + ($x1 - $x2) * $alength / $distance;
    $dy = $y2 + ($y1 - $y2) * $alength / $distance;

    $k = $awidth / $alength;

    $x2o = $x2 - $dx;
    $y2o = $dy - $y2;

    $x3 = $y2o * $k + $dx;
    $y3 = $x2o * $k + $dy;

    $x4 = $dx - $y2o * $k;
    $y4 = $dy - $x2o * $k;

    imagelinethick($img, $x1, $y1, $dx, $dy, $color,3);
    return imagefilledpolygon($img, array($x2, $y2, $x3, $y3, $x4, $y4), 3, $color);
}

This function is called for the line of the arrow (just for your reference):

function imagelinethick($image, $x1, $y1, $x2, $y2, $color, $thick = 1)
{
    /* this way it works well only for orthogonal lines
    imagesetthickness($image, $thick);
    return imageline($image, $x1, $y1, $x2, $y2, $color);
    */
    if ($thick == 1) {
        return imageline($image, $x1, $y1, $x2, $y2, $color);
    }
    $t = $thick / 2 - 0.5;
    if ($x1 == $x2 || $y1 == $y2) {
        return imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
    }
    $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
    $a = $t / sqrt(1 + pow($k, 2));
    $points = array(
        round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
        round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
        round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
        round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
    );
    imagefilledpolygon($image, $points, 4, $color);
    return imagepolygon($image, $points, 4, $color);
}
themerlinproject
  • 3,542
  • 5
  • 37
  • 55

1 Answers1

0

Drawing a slightly larger arrow is going to be problematic, because it won't be the same amount larger at every point. You can draw the arrow in outline color 8 times, offset by 1 pixel for each of 8 directions, then draw the final shape on top of it.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622