raw math

Given a line segment described by two points \(p_1\) and \(p_2\), how is it possible to reduce the length of the line segment by a certain amount \(r\)? In the following I describe the derivation of reducing the length of the line segment at the end point \(p_2\) then the starting point \(p_1\) and finally when the length has to be reduced equally at both ends. For all three cases the line segment can be expressed as a vector \(\vec{v}=(p_2-p_1)\) with magnitude or length \(|\vec{v}|\) and as such the problem is how we can reduce the magnitude of a vector by a certain amount.

Cut the line length at the end

When we cut the length at the end of the line segment we get the following equation to derive the new end point \(p_2'\):

\[\begin{array}{rl} p_2' &= p_1 + \frac{\vec{v}}{|\vec{v}|} \cdot (|\vec{v}| - r)\\ &= p_1 + \vec{v} - \frac{\vec{v}\cdot r}{|\vec{v}|}\\ &= p_1 + \vec{v} \cdot \left(1 - \frac{r}{|\vec{v}|}\right)\\ &= p_1 + (p_2-p_1) \cdot \left(1 - \frac{r}{|(p_2-p_1)|}\right)\\ &= p_1 + p_2 - p_2\frac{r}{|(p_2-p_1)|}-p_1+p_1\frac{r}{|(p_2-p_1)|}\\ &= p_2 - r\frac{p_2-p_1}{|(p_2-p_1)|}\\ \end{array}\]

As a copy and paste solution:

function reduceEnd(p1, p2, r) {
  var dx = p2.x - p1.x;
  var dy = p2.y - p1.y;
  var mag = Math.hypot(dx, dy);
  return {
    x: p2.x - r * dx / mag,
    y: p2.y - r * dy / mag
  };
}

Cut the line length at the beginning

When we cut the length at the beginning of the line segment we get the following equation to derive the new starting point \(p_1'\):

\[\begin{array}{rl} p_1' &= p_2 - \frac{\vec{v}}{|\vec{v}|} \cdot (|\vec{v}| - r)\\ &= p_2 - \vec{v} + \frac{\vec{v}\cdot r}{|\vec{v}|}\\ &= p_2 - \vec{v} \cdot \left(1 - \frac{r}{|\vec{v}|}\right)\\ &= p_2 - (p_2-p_1) \cdot \left(1 - \frac{r}{|(p_2-p_1)|}\right)\\ &= p_2 - p_2 + p_2\frac{r}{|(p_2-p_1)|} + p_1 - p_1\frac{r}{|(p_2-p_1)|}\\ &= p_1 + r\frac{p_2 - p_1}{|(p_2-p_1)|}\\ \end{array}\]

As a copy and paste solution:

function reduceStart(p1, p2, r) {
  var dx = p2.x - p1.x;
  var dy = p2.y - p1.y;
  var mag = Math.hypot(dx, dy);
  return {
    x: p1.x + r * dx / mag,
    y: p1.y + r * dy / mag
  };
}

Cut the line length equally

With the previous derivations it's easy to come up with a solution to cut the amount \(r\) equally at the end and at the beginning of the line segment. That means we offset the line only by \(\frac{r}{2}\) and reduce the end by the same amount. With that, we consecutively apply the first formula and then the second. Since the calculation is made simultaneously, the costly square root must be performed only once:

function reduceEqually(p1, p2, r) {
  var r2 = r / 2;
  var dx = p2.x - p1.x;
  var dy = p2.y - p1.y;
  var mag = Math.hypot(dx, dy);
  return [{
    x: p1.x + r2 * dx / mag,
    y: p1.y + r2 * dy / mag
  }, {
    x: p2.x - r2 * dx / mag,
    y: p2.y - r2 * dy / mag 
  }];
}