From: Peter Dickerson on

"D Yuniskis" <not.going.to.be(a)seen.com> wrote in message
news:hvkecf$843$1(a)speranza.aioe.org...
[snip]
>
> De Casteljau's algorithm.
>
> Given a Start point (S), departing control point (D), arriving
> control point (A), and End point (E), [i.e., these are P0 - P3],
> the control points for the two half curve are:
> M = (D+A)/2
>
> L0 = S
> R3 = E
>
> L1 = (S+D)/2
> R2 = (A+E)/2
>
> L2 = (L1+M)/2
> R1 = (M+R2)/2
>
> L3 = R0 = (L2+R1)/2

[snip]

OK, so it is trivial for cubics. So, you can start with the first estimate
as the average of the control point path and the start to end path. Then
subdivide (binary, say) and get a new estimate. Then combine these estimates
using the Romberg method. Assuming you know the convergence power you can
also estimate the error. If the error is OK keep the result and pass it up,
else recurse again. Somebody somewhere has to decide what good enough is,
perhaps in fractional terms. The benefit of your scheme is that it doesn't
need to recurse so deepy for some parts of the curve as others.

Peter


From: Nobody on
On Sun, 20 Jun 2010 07:35:40 +0100, Peter Dickerson wrote:

> This is the bit I'm missing. How do you get the control points for the two
> halves from the control points of the whole?

b0 = a0
b1 = (a0 + a1)/2
b2 = (a0 + 2*a1 + a2)/4

c0 = b3 = (a0 + 3*a1 + 3*a2 + a3)/8

c1 = (a3 + 2*a2 + a1)/4
c2 = (a3 + a2)/2
c3 = a3

Or, using midpoints only:

b0 = a0
c3 = a3

b1 = (a1 + a0)/2
c2 = (a3 + a2)/2

m = (a1 + a2)/2

b2 = (m + b1)/2
c1 = (m + c2)/2

c0 = b3 = (c1 + b2)/2


From: D Yuniskis on
Hi Paul,

Paul Keinanen wrote:
> On Sat, 19 Jun 2010 10:20:31 -0700, D Yuniskis
> <not.going.to.be(a)seen.com> wrote:
>
>>> Adding/subtracting is easy to do in integer/fixed point arithmetic,
>>> but very nasty to do in floating point format due to demoralization
>> Agreed. Hence my suggestion to leave results "demoralized" ^^^ ;-)
>> at times.
>
> Addition in floating point representation must be done with equal
> exponents, so the smaller value needs to be denormalized to have the
> same exponent as the larger.

Yes, I'm familiar with the issues (I've had to write many floating
point "support" libraries over the years). I think that this would
be a bad fit for a conventional "one-size-fits-all" floating
point implementation. Too many operations are simple arithmetic
(add/sub/div2) and using floats makes those disproportionately
expensive.

> In decimal notation 9.97E03+5.0E01 = 9.97E03+0.05E03 = 10.02E3 =
> 1.002E04. Of course, you could postpone the overflow normalization, if
> other additions/subtractions will immediately follow and if the
> arithmetic unit has sufficient headroom bits.

Exactly. You *know* you are going to compute <blah blah blah>
so come up with a numerical representation that fits the
complexity of the calculations regardless of how "clean" it
is (gee, why bother supporting subnormals, NaN's, etc.?)

>>> and normalization stages. Also integer/fixed to float conversion is
>>> nasty due to normalization.
>>>
>>> Doing sqrt((Xs-Xe)^2+(Ys-Ye)^2) might be easiest to implement by doing
>>> the differences in integer, take abs of both (to reduce table size)
>>> and use a table for squaring and using integer arithmetic for the sum
>>> and then convert to float for sqrt, especially if the result is needed
>>> in floating point representation.
>> Of course, "integer" is really "fixed point" as X(i) and Y(i) are
>> real numbers.
>
> Fixed point add/sub is the same as integer, in multiplication, you
> just have to shift right the result by the number of fractional bits
> etc.
>
>> I don't think a naive "lets use this operator on all values"
>> approach will work effectively. E.g., in regions of low curvature
>> you can get away with bigger segment lengths (eats up a bigger
>> portion of the workload quicker!). And, in high curvature, you
>> quickly fall into the mud trying to get nice tight approximations
>> to sharp curves.
>>
>> So, maybe use floats for the big numbers and a fixed point
>> scheme for the small increments. (or, two different fixed
>> point representations conveniently scaled :> )
>
> As long as you avoid too frequent float/fixed or fixed/float
> conversions in a single expression since (ne)normalization is
> expensive using traditional instruction sets.

For "commodity" processors and/or semicustom logic, I think
a fixed point (though not "integer") scheme is probably going to
be the winner. I need to look at how to cut costs in the basic
algorithm(s). Then, see if there are any tricks I can employ
to further constrain the domain. E.g., perhaps scaling
the coordinates of the points before running the algorithm and
then "de"-scaling the results...

>>> Single cycle normalisation/denormalisation in hardware requires a
>>> barrel shifter capable of shifting multiple bits left or right. For
>>> normalization (to [0.5..1.0] or to [1..2]) a priority encoder is
>>> required to detect the highest bit set, so that the correct shift can
>>> be applied in the barrel shifter.
>> Or, do it all fixed point and just waste bits. E.g., using
>> serial adders and multipliers means you just need to spend
>> money on flip-flops.
>
> Addition, subtraction, multiplication and denormalization can be done
> with right shifting shift registers, however, normalization (and
> division) would also require left shifting shift registers.
>
> _Bit_ serial computing was used a lot in the tube era (and in the
> HP-35 pocket scientific calculator), but I haven't seen it used more
> recently.

I like using serial adders/multipliers when designing dedicated
processors -- i.e., where the algorithm is (literally?) hard-wired.
It's small, easy to debug and scale, etc. E.g., handling 32 bit
values is just as easy as 64 (just add more bits of "data store").
By contrast, going to wider parallel implementations means
having to add *lots* of logic as you add each new bit.

> These days, a huge number of bit serial processors might make sense if
> each serial processor is controlling a single pixel or block of pixels
> and some of these processors could be completely shut down to reduce
> power consumption when no update is required. But otherwise, for equal
> total throughput, both serial and parallel systems would require about
> the same amount of arithmetic elements, but the more complex control
> logic on serial processors would have to be duplicated on more
> processors.
From: D Yuniskis on
Hi Peter,

Peter Dickerson wrote:
> "D Yuniskis" <not.going.to.be(a)seen.com> wrote in message
> news:hvkecf$843$1(a)speranza.aioe.org...
> [snip]
>> De Casteljau's algorithm.
>
> OK, so it is trivial for cubics. So, you can start with the first estimate
> as the average of the control point path and the start to end path. Then
> subdivide (binary, say) and get a new estimate. Then combine these estimates
> using the Romberg method. Assuming you know the convergence power you can

Sorry, you've lost me (easy to do, this early in the morning :< )

> also estimate the error. If the error is OK keep the result and pass it up,

Well, I know that the error can't be more than half of the difference
between the "polygon length" and chord length. I.e., once they
are within 2*error of each other, I *know* the length fits to
within "one error" (?)

> else recurse again. Somebody somewhere has to decide what good enough is,
> perhaps in fractional terms. The benefit of your scheme is that it doesn't
> need to recurse so deepy for some parts of the curve as others.

Well, it *could* not-need to recurse as deeply. It depends on how
tight the curve is. E.g., a (pseudo) circle is probably the worst
"overall" curve to follow as there are *no* "straight runs".

The problem witht he algorithm is that the cost of recursion can
quickly escalate (i.e., the cost of the computations for each
level of recursion is high). And, there is no way of bounding
this a priori. :<
From: Peter Dickerson on
"D Yuniskis" <not.going.to.be(a)seen.com> wrote in message
news:hvqdli$f0l$1(a)speranza.aioe.org...
> Hi Peter,
>
> Peter Dickerson wrote:
>> "D Yuniskis" <not.going.to.be(a)seen.com> wrote in message
>> news:hvkecf$843$1(a)speranza.aioe.org...
>> [snip]
>>> De Casteljau's algorithm.
>>
>> OK, so it is trivial for cubics. So, you can start with the first
>> estimate as the average of the control point path and the start to end
>> path. Then subdivide (binary, say) and get a new estimate. Then combine
>> these estimates using the Romberg method. Assuming you know the
>> convergence power you can
>
> Sorry, you've lost me (easy to do, this early in the morning :< )

Oh! I thought I was reiterating what you were proposing to see if I had it
right.

>> also estimate the error. If the error is OK keep the result and pass it
>> up,
>
> Well, I know that the error can't be more than half of the difference
> between the "polygon length" and chord length. I.e., once they
> are within 2*error of each other, I *know* the length fits to
> within "one error" (?)

Yes, but that bound is quite loose.

>> else recurse again. Somebody somewhere has to decide what good enough is,
>> perhaps in fractional terms. The benefit of your scheme is that it
>> doesn't need to recurse so deepy for some parts of the curve as others.
>
> Well, it *could* not-need to recurse as deeply. It depends on how
> tight the curve is. E.g., a (pseudo) circle is probably the worst
> "overall" curve to follow as there are *no* "straight runs".

Well, the curve can't be tight unless the poly is high order. The order of
the poly, or number of control points hasn't been specified except that
examples have been cubic. Anyway, if you specify that you want the final
error be some small fraction of the initial upper bound then you can use
that fraction on each division of the curve. Or you can assign half the
limit to each half of the division. Not perfect because either way you'll
probably do more work than strictly necessary (but you wouldn't know that
until you'd done all the work...).

> The problem witht he algorithm is that the cost of recursion can
> quickly escalate (i.e., the cost of the computations for each
> level of recursion is high). And, there is no way of bounding
> this a priori. :<

Actually, I don't see it that way at all. In terms of costs I think the
biggest cost is square roots, then perhaps multiples, and then recursion.
The problem that I see is that compute one estimate requires as many square
roots as control points. So for a cubic thats four at the top level and 8 at
the first binary subdivision. The test for whether the upper bound is
sufficiently close to the lower bound can be done on the squared lengths to
save one square root but.

Peter