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