I was not satisfied with the version of the program I posted in post #14. The numerical algorithm I created to find a point (p) on a spline a specified distance (L) from a known point (pt) used a point midway along the spline for the first guess. It then used the bisection numerical method to find p. In some cases, this would not find the closest solution point to pt.

I rewrote the program to assume that the first guess for P was at a distance L, measured along the spline. This will always yield a point too close to pt to be the solution (except if the spline is straight) but not so far away either. From there the algorithm "walks" along the spline at a step size 1/3*L until it passes the solution and then backs up one half the step size until that's too much then goes forward 1/4 the step size. The process is repeated until a location for p within acceptable limits is found.
I think this approach yields much better results for very wavy spline but I am sure there are cases that will yield unacceptable results.
Compare the following solutions via the first method and the new approach.
First method example results:

Improved version:

To get a feel for how the algorithm converges to a solution here is a sample with points placed at the successive guesses made by the program. Note how some solutions are found in as little as 3 guesses.

Points showing successive guesses.

As a side note, I recently posted a tutorial for 3ds Max users on using a similar method to find the point on a cable that is a fixed distance from a trolley with an overhead boom. I think it provides a good explanation how a numerical solution (i.e., a solver) works.
3ds Max Tutorial - creating your own solver
(defun C:ArraySpline (/ L A blockname path pt smax smax dmax sL more p ang sp dpt )
; Adds a series of blocks along a spline. The block's origin is placed on the spline.
; The angle of the block is determined by a second point of the block a distance L in the X
; direction of the block. The block's have a user defined spacing of A.
; L. Minardi 8/9/2023
(command "ucs" "w")
(setvar 'osmode 0)
(setq L (getreal
"\nEnter distance between the block's base point and a point on the block's x axis: "
)
A (getreal "\nEnter distance to next block: ")
blockname (getstring "\nEnter block name: ")
)
;(setq L 1.3 A 1 blockname "block1") ; used for debugging
(setq
path (car (entsel "\nSelect Path."))
pt (vlax-curve-getStartPoint path)
smax (vlax-curve-getEndParam path)
dmax (vlax-curve-getDistAtParam path smax)
sL (vlax-curve-getParamAtDist path L)
more T ; flag for loop
)
(while more ; loop for adding blocks until end of spline is reached
(setq p (SplinePtAtDist path pt L) ; location on spline for block's second point
ang (/ (* (angle pt p) 180.) pi)
)
(command "-insert" blockname pt 1 1 ang)
(setq dp (vlax-curve-getDistAtPoint path p) ; distance to p
sp (vlax-curve-getParamAtPoint path p) ; parameter at p
pt (vlax-curve-getPointAtDist path (+ dp A)) ; next block location
p (vlax-curve-getPointAtDist path (+ dp A L)) ; initial guess for second point on spline
dpt (vlax-curve-getDistAtPoint path pt) ; distance along spline to pt
)
(if (< (- sMax sp) sL) ; test if another block will fit on spline
(setq more nil)
)
) ; end while
(princ)
)
(defun SplinePtAtDist (path pt L / disPt p s spt sDelta i sgn err)
; find the point on a spline that is a distance L from the point pt,
; path - spline object name
; pt - known point on the spline that is closer to the beinning of the spline
; than the desired point p that is a straingt line distance L away.
; L - distance between the block's base point and a point on its x axis.
(setq disPt (vlax-curve-getDistAtPoint path pt)
p (vlax-curve-getPointAtDist path (+ disPt L))
s (vlax-curve-getParamAtPoint path p)
spt (vlax-curve-getParamAtPoint path pt)
sDelta (/ (- s spt) 3)
i 0
sgn 1
)
(while (< i 20) ; sets maximum interations for solution
(if (> L (distance pt p))
(progn ; true, L > distance
(if (> (* sgn -1) 0)
(setq sgn (* sgn -1) ; reverse search diection
sDelta (/ sDelta 2); halve the interval search size
)
)
)
(progn ; false L not > distance
(if (< (* sgn -1) 0)
(setq sgn (* sgn -1)
sDelta (/ sDelta 2)
)
)
)
)
(setq s (+ s (* sgn sDelta))
p (vlax-curve-getPointAtParam path s)
)
;;;(command "point" p) ; used for debugging
(setq i (+ i 1))
(setq err (/ (abs (- (distance pt p) L)) L))
(if (< err 0.001) (setq i 100)) ; exit loop if error acceptable
) ; end while
(setq p p)
) ; end defun
lee.minardi