def _linesegproj(self, qpt, p1, p2): """Projects the query point onto the line segment spanned by p1 and p2. Returns (projected pt, percentage along line p1 -> p2 (which are at 0 and 1), min dist).""" from nkpylib.nkutils import getTriAltitude # get the projection proj = getTriAltitude(qpt, p1, p2) d = -1 for i in range(len(p1)): if p1[i] == p2[i]: continue # find a dimension with some change loc = lerp(proj[i], (p1[i], 0.0), (p2[i], 1.0)) if loc < 0: # off the segment, closer to p1 d = self.distfunc(qpt, p1) break if loc > 1.0: # off the segment, closer to p2 d = self.distfunc(qpt, p2) break # valid projection, so d = its length d = self.distfunc(qpt, proj) break # at this point, if we didn't find any non-zero dimensions, # then we can pick either endpoint as our target. We set location to be None if d < 0: d = self.distfunc(qpt, p1) loc = None return (proj, loc, d)
def interpolate(self, qi): """Finds the linear segment where this query index falls and interpolates values""" idxs = self.indexes i, I = self._nearestindexlocs(qi) if i == I: return self.pts[i] # one of the endpoints # index x, X = idxs[i], idxs[I] # lerp each dim of the output ret = self.copypt(self.pts[0]) for dim, (y, Y) in enumerate(zip(self.pts[i], self.pts[I])): ret[dim] = lerp(qi, (x,y), (X,Y)) return ret
def project(self, qpt): """Projects a query point onto the closest line segment to find its equivalent index and pt. Returns (projected index, projected point, projection distance)""" mind = self.distfunc(qpt, self.pts[0]) ret = (self.indexes[0], self.pts[0], mind) for p1, p2, i1, i2 in zip(self.pts, self.pts[1:], self.indexes, self.indexes[1:]): proj, loc, d = self._linesegproj(qpt, p1, p2) if d > mind: continue # possible candidate for best mind = d # check loc to see whether the projected point is one of the endpoints if loc < 0: # the first point ret = (i1, p1, d) elif loc > 1: # the 2nd point ret = (i2, p2, d) else: # somewhere in between ret = (lerp(loc, (0.0, i1), (1.0, i2)), proj, d) return ret