A replacement for the missing OSL distance to line segment function

The OSL implementation defines but apparently doesn't actually implement the three argument variant of the distance() function. In this short article I present a simple alternative.
While working on a new shader I noticed I got runtime errors that crashed Blender when I used the three argument variant of the distance() function to compute the shortest distance of a point to a line segment. I filed a bug report and although the Blender devs were very quick to verify and respond, the fact remains that it is a gap in the OSL libraries that won't be fixed by the Blender devs (although they have implemented a fix that will prevent Blender from crashing). That leaves us with the task of providing a workaround. Fortunately that is not too difficult.
Finding the shortest distance to a line segment is of course bssic geometry so it was easy enough to find numerous online resources. Based on those (references are in the code below) I came up with the following code:
#include "stdosl.h"

// replacement for the missing distance(p, p1, p2) function

// shortest distance to a line segment from p1 -> p2
// based on information from the following two sites:
// http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
// http://paulbourke.net/geometry/pointlineplane/

float minimum_distance(point v, point w, point p) {
  // Return minimum distance between line segment vw and point p
  vector s = w - v;
  float l2 = dot(s,s);
  if (l2 == 0.0) return distance(p, v);
  float t = dot(p - v, s) / l2;
  if (t < 0.0) return distance(p, v);
  else if (t > 1.0) return distance(p, w);
  vector projection = v + t * (s);
  return distance(p, projection);
}
I will not explain it here, refer to the sources mentioned in the code if you are interested, especially Paul Bourke's site is a treasure trove of useful information.

No comments:

Post a Comment