Contents
raw proof

Partial Polyline drawing

Robert Eisele

Given a polyline with points \(P_1, P_2, \dots P_n\) and vectors \(\mathbf{v}_1, \mathbf{v}_2, \dots \mathbf{v}_{n-1}\) between the points defined as \(\mathbf{v}_k = P_{k} - P_{k-1}\), our goal is to draw \(p\) percent of the polyline path.

The overall length \(L\) of the polyline is given by

\[L=\sum\limits_{k=1}^{n-1}\|P_{k+1}-P_k\|=\sum\limits_{k=1}^{n-1}\|\mathbf{v}_k\|\]

and therefore the length to the desired point on the path is given by \(w=L\cdot p\) for any \(p\in[0, 1]\).

Now the vector \(\mathbf{v}_m\) on the last or \(m\)-th path segment no longer goes from point \(P_m\) to \(P_{m+1}\) but only from \(P_m\) to a point \(Q\) on the segment.

The point \(Q\) is determined by the point \(P_m + \hat{\mathbf{v}}_md\), where \(d\) is the length of the last truncated path segment, that is the desired total length \(w\) minus all segments up to point \(P_m\):

\[d = w - \sum\limits_{k=1}^{m-1}\|\mathbf{v}_k\|\]

Substituting everything into \(Q\) gives:

\[Q = P_m + \hat{\mathbf{v}}_m\left(p\cdot\sum\limits_{k=1}^{n-1}\|\mathbf{v}_k\| - \sum\limits_{k=1}^{m-1}\|\mathbf{v}_k\|\right)\]

If you move in the normalization of \(\mathbf{v}_m\), you get a local percentage value:

\[Q = P_m + {\mathbf{v}}_m\left(\frac{p\cdot\sum\limits_{k=1}^{n-1}\|\mathbf{v}_k\| - \sum\limits_{k=1}^{m-1}\|\mathbf{v}_k\|}{\|\mathbf{v}_m\|}\right)\]

Thus, the following pseudocode for the partial path of a polyline can be found

length = 0
for (k = 1; k < path.length; k++) {
    A = path[k - 1]
    B = path[k]
   length+= norm(B - A)
}

partial = 0
for (k = 1; k < path.length; k++) {

    A = path[k - 1]
    B = path[k]

    d = norm(B - A)

    if (partial + d <= p * length) {
        drawLine(A, B)
    } else {
        drawLine(A, A + (B - A) * (p * length - partial) / d)
        break
    }
    partial+= d
}

Since we calculate partial + d twice, we prefer to perform the addition first, which means we need to subtract partial from the inner once: A + (B - A) * (p * length - (partial - d)) / d, which can be simplified to B + (B - A) * (p * length - partial) / d.

length = 0
for (k = 1; k < path.length; k++) {
    A = path[k - 1]
    B = path[k]
   length+= norm(B - A)
}

partial = 0
for (k = 1; k < path.length; k++) {

    A = path[k - 1]
    B = path[k]

    d = norm(B - A)

    partial+= d
    if (partial <= p * length) {
        drawLine(A, B)
    } else {
        drawLine(A, B + (B - A) * (p * length - partial) / d)
        break
    }
}

Now, if we say that (p * length - partial) / d is the local percentage within segment \(m\), the percentage is \(<0\) if the segment is \(<m\) and \(>1\) for the case that \(>m\). While we do lose the early break, we can eliminate the branch by clamping the local percentage:

length = 0
for (k = 1; k < path.length; k++) {
    A = path[k - 1]
    B = path[k]
   length+= norm(B - A)
}

partial = 0
for (k = 1; k < path.length; k++) {

    A = path[k - 1]
    B = path[k]

    d = norm(B - A)

    partial+= d
    drawLine(A, B + (B - A) * clamp((p * length - partial) / d, 0, 1))
}