From: Frédéric Jolliton
Subject: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <8664abk0vg.fsf@mau.intra.tuxee.net>
Hi,

I'm trying to optimize an algorithm[1] implemented in Common Lisp
borrowed from the C++ project AntiGrain[2]. The algorithm is used to
rasterize polygons with anti-aliasing.

Basically, the part I want to optimize can be summarized as storing a
set of 4-tuple produced by the algorithm, sorting them and iterating
them.

Note: These tuple hold X,Y integers coordinates and 2 integers "COVER"
      and "DELTA". In theory, all these integers are not bounded (and
      all can be negatives) and doesn't necessary fit in FIXNUM, but
      I've decided anyway to declare all these quantities as FIXNUM.

So, given tuples (X,Y,COVER,DELTA), what could be an efficient way to:

 - store them

 - iterate them (once) in a specific order (sorted by Y, then by X)

?

My first attempt[3] was the trivial approach. I created a structure to
hold X,Y,COVER and DELTA, and stored them into a list. Then sorted
this list with SORT, and finally iterated each tuples with a
DOLIST. Amazingly, I was not able to find a better method for the
whole process.

My second attempt was supposedly smarter.. Inspired by the
optimization in AntiGrain, I've created a pool of 2D array of
dimensions (+CHUNK-SIZE+ 4) and of type fixnum (where +CHUNK-SIZE+ is
a constant set to 256 by default.) Then X,Y,COVER and DELTA are stored
in indices 0,1,2 and 3 respectively at increasing position. When an
array is full, I create a new one. This method of storage was 2 times
faster than the first attempt. However, it is less obvious to sort
efficiently. I've created a level of indirection by using an array of
indices, and sorted this array instead. But this is really slow.

I see two others methods:

 * creating a 3D array of dimensions (WIDTH HEIGHT 2) assuming that I
   know the range of X and Y values. Then I can store COVER and DELTA
   into this array directly. No need to sort. But this requires to
   scan the whole array to find non-empty cell. (Also assuming that
   the values are accumulated for a same position, since the algorithm
   can visit the same pixel several times.)

 * creating a hash-table for each Y coordinates encountered, and store
   X,COVER and DELTA in a data structure using idea from the first 2
   attempts. This ensure that sort will be faster, but the price is
   high since this requires to do a gethash before storing each
   tuples.

But I know this will gives worst results.

Does anyone have a better idea about this?



  [1] http://projects.tuxee.net/cl-aa-path/#head-3b945285

  [2] http://antigrain.com/

  [3] http://tuxee.net/cl-aa.lisp

-- 
Fr�d�ric Jolliton

From: Pillsy
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <1171027648.228336.96920@j27g2000cwj.googlegroups.com>
On Feb 9, 6:48 am, Frédéric Jolliton <····@frederic.jolliton.com>
wrote:
[...]
> My second attempt was supposedly smarter.. Inspired by the
> optimization in AntiGrain, I've created a pool of 2D array of
> dimensions (+CHUNK-SIZE+ 4) and of type fixnum (where +CHUNK-SIZE+ is
> a constant set to 256 by default.) Then X,Y,COVER and DELTA are stored
> in indices 0,1,2 and 3 respectively at increasing position. When an
> array is full, I create a new one. This method of storage was 2 times
> faster than the first attempt. However, it is less obvious to sort
> efficiently. I've created a level of indirection by using an array of
> indices, and sorted this array instead. But this is really slow.
[...]
> But I know this will gives worst results.

> Does anyone have a better idea about this?

Instead of a 2D array, try a 1D array of structs or vectors, and then
sort it using plain old SORT with a :KEY argument?

I dunno, it'll probably be slow for the same reason your indirect
solution is slow. If it is, you might want to write your own routine
to sort the 2D array in place.

I frequently find myself wishing I could just treat a N dimensional
array as a vector of (N-1) dimensional arrays and have it work with
the standard CL functions, as is possible in some other languages.
Sigh.

Cheers,
Pillsy
From: Frédéric Jolliton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <863b5fmnps.fsf@mau.intra.tuxee.net>
> On Feb 9, 6:48 am, Fr�d�ric Jolliton <····@frederic.jolliton.com>
> wrote:
> [...]
>> My second attempt was supposedly smarter.. Inspired by the
>> optimization in AntiGrain, I've created a pool of 2D array of
>> dimensions (+CHUNK-SIZE+ 4) and of type fixnum (where +CHUNK-SIZE+ is
>> a constant set to 256 by default.) Then X,Y,COVER and DELTA are stored
>> in indices 0,1,2 and 3 respectively at increasing position. When an
>> array is full, I create a new one. This method of storage was 2 times
>> faster than the first attempt. However, it is less obvious to sort
>> efficiently. I've created a level of indirection by using an array of
>> indices, and sorted this array instead. But this is really slow.
> [...]
>> But I know this will gives worst results.
>
>> Does anyone have a better idea about this?

"Pillsy" <·········@gmail.com> writes:
> Instead of a 2D array, try a 1D array of structs or vectors, and then
> sort it using plain old SORT with a :KEY argument?

But in this case, it gives me the same performance compared to a list,
since (on SBCL), each structure instance is boxed anyway.

> I dunno, it'll probably be slow for the same reason your indirect
> solution is slow. If it is, you might want to write your own routine
> to sort the 2D array in place.

Actually it's more the problem of sorting a *set* of arrays as if they
were a single array. So a custom sort routine wouldn't really help I
think, because the cost is mainly in the computation of the array
number and position into it at each step to compare 2 random elements.

> I frequently find myself wishing I could just treat a N dimensional
> array as a vector of (N-1) dimensional arrays and have it work with
> the standard CL functions, as is possible in some other languages.
> Sigh.

Depending of what you want, you can use displaced array to have
another view of the array with different dimensions. But then, the
array is, of course, no more a simple array.

-- 
Fr�d�ric Jolliton
From: Wade Humeniuk
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <iU%yh.39743$Fd.33755@edtnps90>
You could try a xy-linked-list approach.  Here is some code
(Make sure you set *print-circle* to t before running any tests)
Inserting a tuple puts it into its proper sorted place, both
by x and y.  To iterate through the tuples just use
xy-entry-next-x and xy-entry-next-y.  (Transcript follows code)
I think the code is ok, but it will have to tested more
thouroughly.

(defstruct xy-entry next-x previous-x next-y previous-y)
(defstruct (tuple (:include xy-entry))  x y cover delta)
(defstruct (tuple-root (:include xy-entry)))

(defun init-xy-entry (entry)
   (setf (xy-entry-next-x entry) entry
         (xy-entry-previous-x entry) entry
         (xy-entry-next-y entry) entry
         (xy-entry-previous-y entry) entry)
   entry)

(defun insert-x (entry1 entry2)
   (setf (xy-entry-previous-x entry1) (xy-entry-previous-x entry2)
         (xy-entry-next-x (xy-entry-previous-x entry1)) entry1
         (xy-entry-next-x entry1) entry2
         (xy-entry-previous-x entry2) entry1))

(defun insert-y (entry1 entry2)
   (setf (xy-entry-previous-y entry1) (xy-entry-previous-y entry2)
         (xy-entry-next-y (xy-entry-previous-y entry1)) entry1
         (xy-entry-next-y entry1) entry2
         (xy-entry-previous-y entry2) entry1))

(defun create-tuple-root ()
   (init-xy-entry (make-tuple-root)))

(defun create-tuple (x y cover delta)
   (init-xy-entry (make-tuple :x x :y y :cover cover :delta delta)))

(defun insert-tuple (tuple root)
   (loop for x-tuple = (xy-entry-next-x root) then (xy-entry-next-x x-tuple) do
         (if (eq x-tuple root)
             (progn (insert-x tuple root) (loop-finish))
           (when (<= (tuple-x tuple) (tuple-x x-tuple))
             (insert-x tuple x-tuple)
             (loop-finish))))
   (loop for y-tuple = (xy-entry-next-y root) then (xy-entry-next-y y-tuple) do
         (if (eq y-tuple root)
             (progn (insert-y tuple root) (loop-finish))
           (when (<= (tuple-y tuple) (tuple-y y-tuple))
             (insert-y tuple y-tuple)
             (loop-finish)))))

CL-USER 19 > (setf *print-circle* t)
T

CL-USER 20 > (setf root (create-tuple-root))
#1=#S(TUPLE-ROOT NEXT-X #1# PREVIOUS-X #1# NEXT-Y #1# PREVIOUS-Y #1#)

CL-USER 21 > (insert-tuple (create-tuple 10 5 nil t) root)
NIL

CL-USER 22 > root
#2=#S(TUPLE-ROOT NEXT-X #1=#S(TUPLE NEXT-X #2# PREVIOUS-X #2# NEXT-Y #2# PREVIOUS-Y #2# X 
10 Y 5 COVER NIL DELTA T) PREVIOUS-X #1# NEXT-Y #1# PREVIOUS-Y #1#)

CL-USER 23 > (insert-tuple (create-tuple 5 10 nil t) root)
NIL

CL-USER 24 > root
#3=#S(TUPLE-ROOT NEXT-X #1=#S(TUPLE NEXT-X #2=#S(TUPLE NEXT-X #3# PREVIOUS-X #1# NEXT-Y 
#1# PREVIOUS-Y #3# X 10 Y 5 COVER NIL DELTA T) PREVIOUS-X #3# NEXT-Y #3# PREVIOUS-Y #2# X 
5 Y 10 COVER NIL DELTA T) PREVIOUS-X #2# NEXT-Y #2# PREVIOUS-Y #1#)

CL-USER 25 > (xy-entry-next-x root)
#1=#S(TUPLE NEXT-X #2=#S(TUPLE NEXT-X #3=#S(TUPLE-ROOT NEXT-X #1# PREVIOUS-X #2# NEXT-Y 
#2# PREVIOUS-Y #1#) PREVIOUS-X #1# NEXT-Y #1# PREVIOUS-Y #3# X 10 Y 5 COVER NIL DELTA T) 
PREVIOUS-X #3# NEXT-Y #3# PREVIOUS-Y #2# X 5 Y 10 COVER NIL DELTA T)

CL-USER 26 > (xy-entry-next-x *)
#2=#S(TUPLE NEXT-X #3=#S(TUPLE-ROOT NEXT-X #1=#S(TUPLE NEXT-X #2# PREVIOUS-X #3# NEXT-Y 
#3# PREVIOUS-Y #2# X 5 Y 10 COVER NIL DELTA T) PREVIOUS-X #2# NEXT-Y #2# PREVIOUS-Y #1#) 
PREVIOUS-X #1# NEXT-Y #1# PREVIOUS-Y #3# X 10 Y 5 COVER NIL DELTA T)

CL-USER 27 > (xy-entry-next-x *)
#3=#S(TUPLE-ROOT NEXT-X #1=#S(TUPLE NEXT-X #2=#S(TUPLE NEXT-X #3# PREVIOUS-X #1# NEXT-Y 
#1# PREVIOUS-Y #3# X 10 Y 5 COVER NIL DELTA T) PREVIOUS-X #3# NEXT-Y #3# PREVIOUS-Y #2# X 
5 Y 10 COVER NIL DELTA T) PREVIOUS-X #2# NEXT-Y #2# PREVIOUS-Y #1#)

CL-USER 28 >
From: Frédéric Jolliton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <86sldekyir.fsf@mau.intra.tuxee.net>
Wade Humeniuk <··················@telus.net> writes:
> You could try a xy-linked-list approach.  Here is some code
> (Make sure you set *print-circle* to t before running any tests)
> Inserting a tuple puts it into its proper sorted place, both
> by x and y.  To iterate through the tuples just use
> xy-entry-next-x and xy-entry-next-y.  (Transcript follows code)
> I think the code is ok, but it will have to tested more
> thouroughly.
>
> (defstruct xy-entry next-x previous-x next-y previous-y)
> (defstruct (tuple (:include xy-entry))  x y cover delta)
> (defstruct (tuple-root (:include xy-entry)))
>
> (defun init-xy-entry (entry) ..)
> (defun insert-x (entry1 entry2) ..)
> (defun insert-y (entry1 entry2) ..)
> (defun create-tuple-root () ..)
> (defun create-tuple (x y cover delta) ..)
> (defun insert-tuple (tuple root) ..)

It is an interesting idea, but however it is very memory consuming
(with 4 pointers per structure instances, not counting the header.)
And possibly, too slow for inserting new elements (compared to just
queuing the tuples to sort them all at once at the end.)

My problem seems too low level to approach C (C++) performance here.
(And I want to avoid any FFI at this point.)

But thanks for the suggestion.

-- 
Fr�d�ric Jolliton
From: Wade Humeniuk
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <eHlzh.42066$Oa.30688@edtnps82>
Fr�d�ric Jolliton wrote:
> Wade Humeniuk <··················@telus.net> writes:
>> You could try a xy-linked-list approach.  Here is some code
>> (Make sure you set *print-circle* to t before running any tests)
>> Inserting a tuple puts it into its proper sorted place, both
>> by x and y.  To iterate through the tuples just use
>> xy-entry-next-x and xy-entry-next-y.  (Transcript follows code)
>> I think the code is ok, but it will have to tested more
>> thouroughly.
>>
>> (defstruct xy-entry next-x previous-x next-y previous-y)
>> (defstruct (tuple (:include xy-entry))  x y cover delta)
>> (defstruct (tuple-root (:include xy-entry)))
>>
>> (defun init-xy-entry (entry) ..)
>> (defun insert-x (entry1 entry2) ..)
>> (defun insert-y (entry1 entry2) ..)
>> (defun create-tuple-root () ..)
>> (defun create-tuple (x y cover delta) ..)
>> (defun insert-tuple (tuple root) ..)
> 
> It is an interesting idea, but however it is very memory consuming
> (with 4 pointers per structure instances, not counting the header.)
> And possibly, too slow for inserting new elements (compared to just
> queuing the tuples to sort them all at once at the end.)
> 

 From your comments in other posts I assume your array is sparse.  What
is your x and y (width and height bounds) anyways?

Define memory consuming.  Is it going to eat up your whole machine?
I thought we were in the age of multi-gigabyte machines now.

As for sorting, how is "sorting" all at once better than a sorted
insertion?

> My problem seems too low level to approach C (C++) performance here.
> (And I want to avoid any FFI at this point.)
> 

So you are not going to try??  Oh well.

W

> But thanks for the suggestion.
> 
From: Frédéric Jolliton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <86ire9l9wj.fsf@mau.intra.tuxee.net>
Wade Humeniuk <··················@telus.net> writes:

> Fr�d�ric Jolliton wrote:
[Multi linked list]
>> It is an interesting idea, but however it is very memory consuming
>> (with 4 pointers per structure instances, not counting the header.)
>> And possibly, too slow for inserting new elements (compared to just
>> queuing the tuples to sort them all at once at the end.)

First, sorry, I realize I was probably unclear about the sorting
step. My english is not very good. In fact, when I said "sorting by Y
then by X", I meant sorting by (Y,X). I don't need to scan the
resulting list in 2 manners. Just ensuring than the cells are scanned
top to bottom, left to right.

> From your comments in other posts I assume your array is sparse.
> What is your x and y (width and height bounds) anyways?

Well, X and Y are not necessary directly related to screen
coordinates. In theory, it could be any integer. However, usually,
when rendering on screen, the shape is normally first clipped to the
boundaries of the screen before using the rasterizer, meaning than X
and Y ranges are known in this case.

And, yes, it is very sparse for almost all shapes to be drawn, since
only pixels "on the way" of the path (i.e. contours of the shape) are
accumulated.

> Define memory consuming.  Is it going to eat up your whole machine?
> I thought we were in the age of multi-gigabyte machines now.

Considering a shape to render on a 1024x768 display, moderately
complex, it is true that the number of tuples (cells) is not very
high, maybe around 5k-10k. However, the point is to render many such
shapes in "realtime". But the GC does a good job, so yes, you're right
I should not worry too much. Clearly, "very memory consuming" was
exaggerated.

> As for sorting, how is "sorting" all at once better than a sorted
> insertion?

I was referring to the linear time to insert each new element in your
data structure. But since you made it such that it can be iterated in
2 differents ways, my comment doesn't hold, since I was comparing it
to a different method.

But.. this gave me an idea. Since I follow the path of the shape, the
coordinates are almost always close from one tuple to the next
one. So, I tried a standard double-linked list, with a pointer to the
last inserted tuple, and I search backward/forward the place to insert
a new tuple. My first measure seems to indicate a win in
performance. I think I could even use skip list.

-- 
Fr�d�ric Jolliton
From: Wade Humeniuk
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <JUxAh.62827$Fd.56303@edtnps90>
Fr�d�ric Jolliton wrote:
> 
> But.. this gave me an idea. Since I follow the path of the shape, the
> coordinates are almost always close from one tuple to the next
> one. So, I tried a standard double-linked list, with a pointer to the
> last inserted tuple, and I search backward/forward the place to insert
> a new tuple. My first measure seems to indicate a win in
> performance. I think I could even use skip list.
> 

So...  How much of a win?  3x, 4x, 100x?

W
From: Frédéric Jolliton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <86r6ssvlwk.fsf@mau.intra.tuxee.net>
Wade Humeniuk <··················@telus.net> writes:

> Fr�d�ric Jolliton wrote:
>>
>> But.. this gave me an idea. Since I follow the path of the shape, the
>> coordinates are almost always close from one tuple to the next
>> one. So, I tried a standard double-linked list, with a pointer to the
>> last inserted tuple, and I search backward/forward the place to insert
>> a new tuple. My first measure seems to indicate a win in
>> performance. I think I could even use skip list.

> So...  How much of a win?  3x, 4x, 100x?

Not much. 2x compared to a single list sorted at the end.

I've also tried a 2 levels linked-list (a linked-list of linked-list
of cell). One level for the Y axis, and the second one for the X
axis. Keeping a pointer to the last inserted element on each level,
then looking up where to update/insert a new element starting from the
last one. But it doesn't perform better.

Likewise for a 2 levels hash-table (as expected.)

-- 
Fr�d�ric Jolliton
From: Wade Humeniuk
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <V%uzh.50217$Y6.15946@edtnps89>
On testing, using filling a list then sorting is much faster.

Wade
From: Ken Tilton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <GNqzh.51$q%4.45@newsfe11.lga>
Fr�d�ric Jolliton wrote:
> Hi,
> 
> I'm trying to optimize an algorithm[1] implemented in Common Lisp
> borrowed from the C++ project AntiGrain[2]. The algorithm is used to
> rasterize polygons with anti-aliasing.
> 
> Basically, the part I want to optimize can be summarized as storing a
> set of 4-tuple produced by the algorithm, sorting them and iterating
> them.
> 
> Note: These tuple hold X,Y integers coordinates and 2 integers "COVER"
>       and "DELTA". In theory, all these integers are not bounded (and
>       all can be negatives) and doesn't necessary fit in FIXNUM, but
>       I've decided anyway to declare all these quantities as FIXNUM.
> 
> So, given tuples (X,Y,COVER,DELTA), what could be an efficient way to:
> 
>  - store them
> 
>  - iterate them (once) in a specific order (sorted by Y, then by X)
> 
> ?
> 
> My first attempt[3] was the trivial approach. I created a structure to
> hold X,Y,COVER and DELTA, and stored them into a list. Then sorted
> this list with SORT, and finally iterated each tuples with a
> DOLIST. Amazingly, I was not able to find a better method for the
> whole process.
> 
> My second attempt was supposedly smarter.. Inspired by the
> optimization in AntiGrain, I've created a pool of 2D array of
> dimensions (+CHUNK-SIZE+ 4) and of type fixnum (where +CHUNK-SIZE+ is
> a constant set to 256 by default.) Then X,Y,COVER and DELTA are stored
> in indices 0,1,2 and 3 respectively at increasing position. When an
> array is full, I create a new one. This method of storage was 2 times
> faster than the first attempt. However, it is less obvious to sort
> efficiently. I've created a level of indirection by using an array of
> indices, and sorted this array instead. But this is really slow.
> 
> I see two others methods:
> 
>  * creating a 3D array of dimensions (WIDTH HEIGHT 2) assuming that I
>    know the range of X and Y values. Then I can store COVER and DELTA
>    into this array directly. No need to sort. But this requires to
>    scan the whole array to find non-empty cell. (Also assuming that
>    the values are accumulated for a same position, since the algorithm
>    can visit the same pixel several times.)
> 
>  * creating a hash-table for each Y coordinates encountered, and store
>    X,COVER and DELTA in a data structure using idea from the first 2
>    attempts. This ensure that sort will be faster, but the price is
>    high since this requires to do a gethash before storing each
>    tuples.
> 
> But I know this will gives worst results.
> 
> Does anyone have a better idea about this?
> 
> 
> 
>   [1] http://projects.tuxee.net/cl-aa-path/#head-3b945285
> 
>   [2] http://antigrain.com/
> 
>   [3] http://tuxee.net/cl-aa.lisp
> 

[4] http://common-lisp.net/project/cffi/

And I offer that having seen your stated later desire not to use FFI (so 
  I must really mean it).

Unless this is just an exercise in learning to write fast Lisp (in which 
case you can stop reading) and not at all related to actually using the 
Antigraing technology, you have already invested more energy than it 
would have taken to carve out a DLL and learn a little CFFI -- don't 
forget, there are folks here and over at the CFFI list that can help 
with that, too.

The only difference is that, having mastered CFFI, a whole world of 
libraries are opened to you.

I agree it would be great to do everything in Lisp, but I look at it 
this way: the C library is probably not what I want to do with Lisp, I 
probably want to be drawing insanely beautiful pictures with 
anti-aliased polygons. So I just use the C library and get on with what 
I really want to do. In Lisp.

ymmv,kzo




-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Zach Beane
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <m31wkxpsx3.fsf@unnamed.xach.com>
Ken Tilton <·········@gmail.com> writes:

> I agree it would be great to do everything in Lisp, but I look at it
> this way: the C library is probably not what I want to do with Lisp, I
> probably want to be drawing insanely beautiful pictures with
> anti-aliased polygons. So I just use the C library and get on with
> what I really want to do. In Lisp.

Sometimes there's value in doing it yourself in Lisp. Skippy has
turned out to be much faster than ImageMagick at reading and writing
GIFs with hundreds of small frames. Those happen to be exactly the
types of GIFs I want to generate and process. It was also a nice
learning experience.

The "insanely beautiful pictures" bit reminds me of something I've
noticed about people who want to use Lisp, but don't because of
reasons like "it can't generate standalone executables." Yeah, it
would be nice if all such features were very easy to get at no cost,
but the challenge is actually /producing/ something of value, not some
(relatively minor) technical detail of production. Having a great Lisp
graphics library doesn't make you able to produce anything of
value. I've seen your GUI demos.

Zach
From: Zach Beane
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <m3slddoe7i.fsf@unnamed.xach.com>
Zach Beane <····@xach.com> writes:

> Having a great Lisp graphics library doesn't make you able to
> produce anything of value. I've seen your GUI demos.

"Value", here, in the "insanely beautiful" sense.

Zach
From: Ken Tilton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <N8szh.37$k77.3@newsfe12.lga>
Zach Beane wrote:
> Zach Beane <····@xach.com> writes:
> 
> 
>>Having a great Lisp graphics library doesn't make you able to
>>produce anything of value. I've seen your GUI demos.
> 

Not spinning in 3D going woo-woo-woo, you haven't:

    http://www.tilton-technology.com/jmcube.jpg

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Frédéric Jolliton
Subject: Re: Optimizing an algorithm used to rasterize polygons
Date: 
Message-ID: <86hcttl9w3.fsf@mau.intra.tuxee.net>
Ken Tilton <·········@gmail.com> writes:

> Fr�d�ric Jolliton wrote:
>> I'm trying to optimize an algorithm[1] implemented in Common Lisp
>> borrowed from the C++ project AntiGrain[2]. The algorithm is used to
>> rasterize polygons with anti-aliasing.
[..]
> [4] http://common-lisp.net/project/cffi/
>
> And I offer that having seen your stated later desire not to use FFI
> (so I must really mean it).
>
> Unless this is just an exercise in learning to write fast Lisp (in
> which case you can stop reading) and not at all related to actually
> using the Antigraing technology, you have already invested more energy
> than it would have taken to carve out a DLL and learn a little CFFI --
> don't forget, there are folks here and over at the CFFI list that can
> help with that, too.

AntiGrain use templates a *lot*. Almost everywhere. So CFFI is not of
a great help. When I made a module for the Python language to use
AntiGrain I had to choose what templates to instantiates statically.

And of course, C++ is great for performance, Python is great for high
level stuff.. but I prefer Common Lisp doing everything and providing
performance and high level at the same time. I've done enough C and
C++ in my life.

> The only difference is that, having mastered CFFI, a whole world of
> libraries are opened to you.

I know CFFI. I use it in some other projects (even a public one[1].)

> I agree it would be great to do everything in Lisp,

And it is my main point in doing this library. We cannot eternally
rely on C. I'm ready to accept less performance if I know that all the
code is written in Common Lisp, because it mean to me that it more
tweakable, easier to maintain, *portable* across implementations
(while the underlying C library is not necessary portable) and so on.

> but I look at it this way: the C library is probably not what I want
> to do with Lisp, I probably want to be drawing insanely beautiful
> pictures with anti-aliased polygons. So I just use the C library and
> get on with what I really want to do. In Lisp.

And you're right. For a commercial project, in the same case, I would
probably choose an existing C library over rewriting the same thing in
Common Lisp if possible. Nonetheless, the project started because I
wanted to understand the algorithm. And rewriting it in Common Lisp
was a way to achieve that. Releasing it was just another step. And
now, to make this library useful, I'm building a path library on top
of it. But that's just consequences. Nothing really planned. I've too
much free time anyway :)



  [1] http://projects.tuxee.net/cl-chmlib/

-- 
Fr�d�ric Jolliton