Added non-uniform sampling to deriv and uniform option to

path_tangents, and path_segment_lengths.
This commit is contained in:
Adrian Mariano 2020-06-13 22:35:22 -04:00
parent 57034ac955
commit a5753d7953
2 changed files with 69 additions and 4 deletions

View File

@ -899,7 +899,13 @@ function count_true(l, nmax=undef, i=0, cnt=0) =
// data[len(data)-1]. This function uses a symetric derivative approximation
// for internal points, f'(t) = (f(t+h)-f(t-h))/2h. For the endpoints (when closed=false) the algorithm
// uses a two point method if sufficient points are available: f'(t) = (3*(f(t+h)-f(t)) - (f(t+2*h)-f(t+h)))/2h.
//
// If `h` is a vector then it is assumed to be nonuniform, with h[i] giving the sampling distance
// between data[i+1] and data[i], and the data values will be linearly resampled at each corner
// to produce a uniform spacing for the derivative estimate. At the endpoints a single point method
// is used: f'(t) = (f(t+h)-f(t))/h.
function deriv(data, h=1, closed=false) =
is_vector(h) ? _deriv_nonuniform(data, h, closed=closed) :
let( L = len(data) )
closed? [
for(i=[0:1:L-1])
@ -919,6 +925,28 @@ function deriv(data, h=1, closed=false) =
];
function _dnu_calc(f1,fc,f2,h1,h2) =
let(
f1 = h2<h1 ? lerp(fc,f1,h2/h1) : f1 ,
f2 = h1<h2 ? lerp(fc,f2,h1/h2) : f2
)
(f2-f1) / 2 / min([h1,h2]);
function _deriv_nonuniform(data, h, closed) =
assert(len(h) == len(data)-(closed?0:1),str("Vector valued h must be length ",len(data)-(closed?0:1)))
let(
L = len(data)
)
closed? [for(i=[0:1:L-1])
_dnu_calc(data[(L+i-1)%L], data[i], data[(i+1)%L], select(h,i-1), h[i]) ]
: [
(data[1]-data[0])/h[0],
for(i=[1:1:L-2]) _dnu_calc(data[i-1],data[i],data[i+1], h[i-1],h[i]),
(data[L-1]-data[L-2])/h[L-2]
];
// Function: deriv2()
// Usage: deriv2(data, [h], [closed])
// Description:

View File

@ -149,6 +149,21 @@ function path_length(path,closed=false) =
sum([for (i = [0:1:len(path)-2]) norm(path[i+1]-path[i])])+(closed?norm(path[len(path)-1]-path[0]):0);
// Function: path_segment_lengths()
// Usage:
// path_segment_lengths(path,[closed])
// Description:
// Returns list of the length of each segment in a path
// Arguments:
// path = path to measure
// closed = true if the path is closed. Default: false
function path_segment_lengths(path, closed=false) =
[
for (i=[0:1:len(path)-2]) norm(path[i+1]-path[i]),
if (closed) norm(path[0]-path[len(path)-1])
];
// Function: path_pos_from_start()
// Usage:
// pos = path_pos_from_start(path,length,[closed]);
@ -280,13 +295,35 @@ function path_closest_point(path, pt) =
// Function: path_tangents()
// Usage: path_tangents(path, [closed])
// Usage: path_tangents(path, [closed], [uniform])
// Description:
// Compute the tangent vector to the input path. The derivative approximation is described in deriv().
// The returns vectors will be normalized to length 1.
function path_tangents(path, closed=false) =
// The returns vectors will be normalized to length 1. If any derivatives are zero then
// the function fails with an error. If you set `uniform` to false then the sampling is
// assumed to be non-uniform and the derivative is computed with adjustments to produce corrected
// values.
// Arguments:
// path = path to find the tagent vectors for
// closed = set to true of the path is closed. Default: false
// uniform = set to false to correct for non-uniform sampling. Default: true
// Example: A shape with non-uniform sampling gives distorted derivatives that may be undesirable
// rect = square([10,3]);
// tangents = path_tangents(rect,closed=true);
// stroke(rect,closed=true, width=0.1);
// color("purple")
// for(i=[0:len(tangents)-1])
// stroke([rect[i]-tangents[i], rect[i]+tangents[i]],width=.1, endcap2="arrow2");
// Example: A shape with non-uniform sampling gives distorted derivatives that may be undesirable
// rect = square([10,3]);
// tangents = path_tangents(rect,closed=true,uniform=false);
// stroke(rect,closed=true, width=0.1);
// color("purple")
// for(i=[0:len(tangents)-1])
// stroke([rect[i]-tangents[i], rect[i]+tangents[i]],width=.1, endcap2="arrow2");
function path_tangents(path, closed=false, uniform=true) =
assert(is_path(path))
[for(t=deriv(path,closed=closed)) unit(t)];
!uniform ? [for(t=deriv(path,closed=closed, h=path_segment_lengths(path,closed))) unit(t)]
: [for(t=deriv(path,closed=closed)) unit(t)];
// Function: path_normals()