From: D Yuniskis on
Hi Paul,

Paul Keinanen wrote:
> On Mon, 14 Jun 2010 18:23:44 -0700, D Yuniskis
> <not.going.to.be(a)seen.com> wrote:
>
>> But, that's still a lot of number crunching! If I work
>> in a quasi fixed point representation of the space, it
>> still leaves me with lots of sqrt() operations (which
>> are hard to reduce to table lookups in all but a trivial
>> space! :< )
>
> What kind of representation are you using (number of bits, binary
> point location) and how many bits should the length have ?

Part of the reason for the question is to see just how far into
the mud I can drive these issues.

Note that the precision of all the math plays a role in the
magnitude of the error (and accumulated error) -- not just
the "cost" of the operation (space + time).

If the curve is constrained to an N.0 x N.0 bit rectangular space
(2D curves, not the 3D curves illustrated in the example
George posted), then the length of the longest such curve
would probably be ~4N.

Note, however, that the control points for such curves could
conceivably lie beyond that NxN space -- without violating
this constraint. I think 2Nx2N would be a safe assumption
for them (i.e., this affects *some* of the math as the points
must be representable, computationally).

Sorting out how far to the right of the binary point to
carry computations is a lot harder without constraints on
the curves themselves. What I have been trying to do is
just code a generic "text book" algorithm and allow me to
pass masks to it that essentially discard precision after
each (floating point) operation just so I can see how this
affects the results FOR SAMPLE CURVES. I.e., an empirical
analysis instead of a theoretical one. Hopefully, it will
give me a handle on what I can get away with computationally.
And, let me experiment with different characteristics of
curves to see what aggravates the math the most/least!

> How expensive is the sqrt using the hardware (if it exists) or using
> the standard run time library (which must also handle special cases) ?

Think in terms of "days of yore" :> I.e., I am trying to
drive the algorithm to a point where I can get by with just
shifts and adds (instead of multiplication, division, etc.).

> A huge table could be replaced with a shift, two table lookups, one
> multiply and one odd.

Ideally, I can find a numeric representation and algorithm that
I can push into silicon. I don't see any way to get around the
sqrt operator but doing that via CORDIC wouldn't be too
expensive if I *really* want to can the whole thing.

> If the sqrt argument is in floating point format, the exponent is
> divided by 2 and the normalized could go through a table lookup. A
> single step normalization (increment exponent by one, shift right
> mantissa by one bit) may be required.

I think you can cheat even more *knowing* what subsequent operations
*will* be. E.g., postpone the normalization until after the sums
have been computed, etc. Small optimizations but they might
save a bit of time and precision.

> A suitable floating point representation would be 1 byte 2's
> complement exponent and 16 bit mantissa (without any hidden bit
> tricks).

The problem is deciding what constitutes "suitable" from a
computational aspect -- as you accumulate "length", you can't
sacrifice "resolution". E.g., even if N is only 10-12 bits,
you quickly eat up that 16 bits as you are often summing
very small segment lengths where you want to *carry* that
precision in your sum (yet are forced to discard it as
the accumulated length increases and consumes bits in your
representation).

I'm just trying to get a handle on how *best* to approach
the algorithm itself so I can better evaluate the consequences
of any representation scheme on the "goodness" of the results.
Then, see what it all *costs* :-/
From: D Yuniskis on
Hi Peter,

Peter Dickerson wrote:
> "Walter Banks" <walter(a)bytecraft.com> wrote in message
> news:4C1828BA.DEF4C9(a)bytecraft.com...
>>
>> Tim Wescott wrote:
>>
>>> Since Bezier curves are polynomial, can't you find an exact solution for
>>> each segment and solve it? Or is that what you find too expensive?
>>>
>>> (This could be a naive question -- I haven't done the math to see how
>>> complicated the answer is).
>>>
>> The math everyone is avoiding is for each line segment
>> Xl = Xs-Xe; // X end points
>> Yl = Ys-Ye; // Y end points
>> len = sqrt( (Xl * Xl) + (Yl *Yl));
>>
>> For lots of short segments.
>
> Yes, but that's like numerically integrating exp(x) step by step because you
> don't know how to do integration using algebra. Of course, it may be that
> its much more like exp(-x^2)...
>
> Even for numeric integration can't you use a Romberg style scheme:
>
> You can compute the length exactly by summing infinitely small linear
> segments. Call this L0. If instead you use finite step size h of the control
> parameter then the approximation will be L[h] = L0+O(h^n) for some n (n is
> typically an integer but haven't checked for Beziers).
>
> Let's say L[h] = L0 + k*(h^n) + O(h^m) with m > n
>
> the do the integration again with a different step size. For simplicity, say
> 2h, which has the advantage that it can share much of the calculation. Then
> we'd expect
>
> L[2h] = L0 + k*((2h)^n) + O(h^m).
>
> so now (2^n)*L[h] - L[2h] = ((2^n)-1)*L0 + O(h^m) i.e. h^n term has been
> cancelled.
>
> So a new estimate of L0 is
> L0 = ((2^n)*L[h] - L[2h])/((2^n)-1) + O(h^m)
> which converges more quickly with reducing h than does the original.
>
> Note that this says nothing about how you calculate the length only about
> how to get a better estimate from two poor estimates. The point being that
> the size of h you can get away with can be much larger and so the overall
> amount of work can be (much) less.
>
> Still, I'm with Tim on this one. Try some math(s) first.

Working the numbers from "t" leaves you burning through lots of
iterations of "oops, too big!" before you can get to suitably
small increments that give you close enough approximations
(there has been a LOT of research on this problem as it is so
commonly used to represent curves/surfaces :< ).

Unless you can constrain the shapes of the curves, there is
nothing you can do a priori (in your algorithm) to guarantee
that an approach, choice of t, etc. will work.

E.g., years ago, I wrote an algorithm to draw lines of
constant time-difference for a LORAN-C pen plotter. Basically,
families of "concentric" (?) hyperbolae. But, you can't know
a priori where on the family of curves you will be operating
so the algorithm had to handle all cases. Computing *a*
point on the curve took a full second -- you can't
compute many such points before the user will grow impatient
with you :>

But, this computation may just end up telling you, "I can't
get to that point with a linear approximation as there is
too much curvature here". So, you just *wasted* a second.
Watching the algorithm creep into regions of increasing
curvature was *painful* (as each successive estimate got
"less good")

So, you sort out how you can get *some* information from
the datum that, hopefully, makes your next actions a *little*
bit better -- or, maybe not as painfully *bad*!

This algorithm (bezier length) isn't *nearly* as expensive.
But, the same applies: make every computation "count"
(towards achieving your final goal).
From: Peter Dickerson on
"D Yuniskis" <not.going.to.be(a)seen.com> wrote in message
news:hvap1i$vdt$1(a)speranza.aioe.org...
> Hi Peter,
>
> Peter Dickerson wrote:
>> "Walter Banks" <walter(a)bytecraft.com> wrote in message
>> news:4C1828BA.DEF4C9(a)bytecraft.com...
>>>
>>> Tim Wescott wrote:
>>>
>>>> Since Bezier curves are polynomial, can't you find an exact solution
>>>> for
>>>> each segment and solve it? Or is that what you find too expensive?
>>>>
>>>> (This could be a naive question -- I haven't done the math to see how
>>>> complicated the answer is).
>>>>
>>> The math everyone is avoiding is for each line segment
>>> Xl = Xs-Xe; // X end points
>>> Yl = Ys-Ye; // Y end points
>>> len = sqrt( (Xl * Xl) + (Yl *Yl));
>>>
>>> For lots of short segments.
>>
>> Yes, but that's like numerically integrating exp(x) step by step because
>> you don't know how to do integration using algebra. Of course, it may be
>> that its much more like exp(-x^2)...
>>
>> Even for numeric integration can't you use a Romberg style scheme:
>>
>> You can compute the length exactly by summing infinitely small linear
>> segments. Call this L0. If instead you use finite step size h of the
>> control parameter then the approximation will be L[h] = L0+O(h^n) for
>> some n (n is typically an integer but haven't checked for Beziers).
>>
>> Let's say L[h] = L0 + k*(h^n) + O(h^m) with m > n
>>
>> the do the integration again with a different step size. For simplicity,
>> say 2h, which has the advantage that it can share much of the
>> calculation. Then we'd expect
>>
>> L[2h] = L0 + k*((2h)^n) + O(h^m).
>>
>> so now (2^n)*L[h] - L[2h] = ((2^n)-1)*L0 + O(h^m) i.e. h^n term has been
>> cancelled.
>>
>> So a new estimate of L0 is
>> L0 = ((2^n)*L[h] - L[2h])/((2^n)-1) + O(h^m)
>> which converges more quickly with reducing h than does the original.
>>
>> Note that this says nothing about how you calculate the length only about
>> how to get a better estimate from two poor estimates. The point being
>> that the size of h you can get away with can be much larger and so the
>> overall amount of work can be (much) less.
>>
>> Still, I'm with Tim on this one. Try some math(s) first.
>
> Working the numbers from "t" leaves you burning through lots of
> iterations of "oops, too big!" before you can get to suitably
> small increments that give you close enough approximations
> (there has been a LOT of research on this problem as it is so
> commonly used to represent curves/surfaces :< ).

but probably fewer than the naive approach with the same the same degree of
non-contraint on the problem.

> Unless you can constrain the shapes of the curves, there is
> nothing you can do a priori (in your algorithm) to guarantee
> that an approach, choice of t, etc. will work.

it isn't an algoritm per se, its an optimization to avoid finer step sizes.

> E.g., years ago, I wrote an algorithm to draw lines of
> constant time-difference for a LORAN-C pen plotter. Basically,
> families of "concentric" (?) hyperbolae. But, you can't know
> a priori where on the family of curves you will be operating
> so the algorithm had to handle all cases. Computing *a*
> point on the curve took a full second -- you can't
> compute many such points before the user will grow impatient
> with you :>

years ago I wrote a rotine to plot mass spectra which involved solving
cubics for it data point on an early 68k machine. A couple of thousand data
points plotted as fast as anyone would care about, <1s. No hardware FP,
avoided sqrt in most cases...

> But, this computation may just end up telling you, "I can't
> get to that point with a linear approximation as there is
> too much curvature here". So, you just *wasted* a second.
> Watching the algorithm creep into regions of increasing
> curvature was *painful* (as each successive estimate got
> "less good")

in this case the previous and current result are used to improve the
estimate in the hope of going to higher resolution.

> So, you sort out how you can get *some* information from
> the datum that, hopefully, makes your next actions a *little*
> bit better -- or, maybe not as painfully *bad*!
>
> This algorithm (bezier length) isn't *nearly* as expensive.
> But, the same applies: make every computation "count"
> (towards achieving your final goal).

peter


From: Hans-Bernhard Bröker on
Tim Wescott wrote:

> Since Bezier curves are polynomial, can't you find an exact solution for
> each segment and solve it?

For the polynomials you can't. The catch is that they're polynomial in
the curve parameter, not in one of the coordinates. The exact solution
for a third-degree Bezier spline would involve integrating the square
root of a 4th-degree polynomial. Closed-form exact solutions for that
don't exist.

From: D Yuniskis on
Hi Peter,

Peter Dickerson wrote:
>>> Note that this says nothing about how you calculate the length only about
>>> how to get a better estimate from two poor estimates. The point being
>>> that the size of h you can get away with can be much larger and so the
>>> overall amount of work can be (much) less.
>>>
>>> Still, I'm with Tim on this one. Try some math(s) first.
>> Working the numbers from "t" leaves you burning through lots of
>> iterations of "oops, too big!" before you can get to suitably
>> small increments that give you close enough approximations
>> (there has been a LOT of research on this problem as it is so
>> commonly used to represent curves/surfaces :< ).
>
> but probably fewer than the naive approach with the same the same degree of
> non-contraint on the problem.

What's the "naive approach"? The algorithm I outlined drills
down to increasingly finer segment sizes until it achieves a
desired level of "fit". If the curve is *linear*, the length
is computed as the distance between the endpoints!

>> Unless you can constrain the shapes of the curves, there is
>> nothing you can do a priori (in your algorithm) to guarantee
>> that an approach, choice of t, etc. will work.
>
> it isn't an algoritm per se, its an optimization to avoid finer step sizes.
>
>> E.g., years ago, I wrote an algorithm to draw lines of
>> constant time-difference for a LORAN-C pen plotter. Basically,
>> families of "concentric" (?) hyperbolae. But, you can't know
>> a priori where on the family of curves you will be operating
>> so the algorithm had to handle all cases. Computing *a*
>> point on the curve took a full second -- you can't
>> compute many such points before the user will grow impatient
>> with you :>
>
> years ago I wrote a rotine to plot mass spectra which involved solving
> cubics for it data point on an early 68k machine. A couple of thousand data
> points plotted as fast as anyone would care about, <1s. No hardware FP,
> avoided sqrt in most cases...

Then you weren't working in a resource starved environment. :>
(e.g., the plotter ran on a 3MHz 8085, 10KB of code and 512 bytes
of RAM -- for the entire instrument!).

I've found that failing to meet a ~300ms response time
WITH A CLEVER ALGORITHM is a good shirtcuff definition for
resource starved. E.g., if I push a button and can perceive
the delay in the attendant action, then the code is
struggling to do more than it can...

>> But, this computation may just end up telling you, "I can't
>> get to that point with a linear approximation as there is
>> too much curvature here". So, you just *wasted* a second.
>> Watching the algorithm creep into regions of increasing
>> curvature was *painful* (as each successive estimate got
>> "less good")
>
> in this case the previous and current result are used to improve the
> estimate in the hope of going to higher resolution.

Yes, as does the algorithm I proposed. If the points you end up
with don't look to be a good fit, you subdivide and try again
(recurse). Using the first control polygon and the subsequent
subdivided points as upper and lower limits on the "actual"
value lets you come up with a numerical factor that bounds
your error: i.e., the length is in [a,b] - which you can
examine at run time and use to decide if you need to further
subdivide. Watching how a and b vary with each refinement
lets you see when you are just spinning your wheels.

>> So, you sort out how you can get *some* information from
>> the datum that, hopefully, makes your next actions a *little*
>> bit better -- or, maybe not as painfully *bad*!
>>
>> This algorithm (bezier length) isn't *nearly* as expensive.
>> But, the same applies: make every computation "count"
>> (towards achieving your final goal).