I should probably document this color-thing somewhat.

>From a top down view, let's pretend that I researched how we perceive
color (and how this can vary from person to person), and how that
relates to various implementations of how computers implement color.
But really, this is something of cubic representation of color, with
the slider representing the white-black range, and the colored part
representing a cross section of that cube perpendicular to the
white/black axis.

Anyways, this line:

CORNERSETS=: ((+/&.:*:"1) <@(({~ giftwrap)^:(6=#))@~./. ]) ,/(([ +"1
(85%~i.86) */ -~)/)"2 ((#~ </"1)8 8 #:I. ,/1=|+/&.:  *:"1 -"1/~ #:i.8)
{ #:i.8

represents that cube.

This value - CORNERSETS - is a boxed list with 256.  The first box
represents black (color: 0 0 0 - red, green, blue) and the last box
represents white (color: 1 1 1). This concept of representing a color
as a sequence of three numbers in the range 0..1 is convenient for use
with opengl.

The rest of the boxes contain slices of a polygon (either three sided
or six sided) corresponding to a slice across a color cube
perpendicular to the white/black access.  Each element of a box can be
thought of as an rgb color value, or as a corner of the face of a
polygon.

So let's go bottom-up, for a bit, to see how this gets constructed.

A cube has eight corners, and we can number them:
   i. 8
0 1 2 3 4 5 6 7

The binary representation of these numbers can be thought of as rgb
coordinates for these eight colors.
   #:i.8
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

But that's not enough for the color palette that I wanted. I want not
just the corners, but lines between them.  And, for that, I decided to
pair up adjacent corners, so that I could draw lines between them.
That's this:

    ((#~ </"1)8 8 #:I. ,/1=|+/&.:*:"1 -"1/~ #:i.8) { #:i.8

The part in parenthesis first finds differences between all corner pairs:
   -"1/~ #:i.8

and then finds the distance described by that pair
   +/&.:*:"1 -"1/~ #:i.8

And then I take an absolute value for no good reason - it's a holdover
from an earlier version that's not useful here.  (I built this code
"artistically" - thinking of the effect I wanted and using trial and
error, based on appearance and taste, and then posted it before doing
any final cleanup - I felt that give some of you some of the flavor of
my code building process might be useful to you?)

Anyways, the edges I am interested in have a length of 1, so that's
easy to define:
   1=+/&.:*:"1 -"1/~ #:i.8

wait, I'm throwing away all that work! oh no!

But the interesting bit is in the coordinates of the array, so I
haven't lost anything essential here.  All I need to do is ravel it
and use I. and I almost have the coordinates of the interesting edges.
 (And I should have just used , instead of ,/ to flatten the cube - at
the time I wrote it, I wasn't thinking clearly there - ,/ gets rid of
just the leading dimension, and I was not looking at my data and had
forgotten that I only had two dimensions here.)  But the problem with
I., is that I just get a single number for each 1 bit, and I want a
pair of numbers.  But I can recover the information as separate
numbers by using an octal representation:

   8 8 #:I.,1=+/&.:*:"1 -"1/~ #:i.8

That gives me 24 rows of result, and a cube only has 12 edges. I went
a bit over board here, and am representing each edge twice.  I can
throw away half of them, but which half?  One easy approach discards
edges where the first index is greater than the second index.  (#~
</"1) accomplishes this, but there's another way:

   ~./:"1~8 8 #:I.,1=+/&.:*:"1 -"1/~ #:i.8
0 1
0 2
0 4
1 3
1 5
2 3
2 6
3 7
4 5
4 6
5 7
6 7

Now all I need are the corresponding rgb values for each of these cube
indices.  I had used (expression) { #:i.8 to get those values, but
there's another way:

      #: ~./:"1~8 8 #:I.,1=+/&.:*:"1 -"1/~ #:i.8

Here, I've a rank three array:

   $#:~./:"1~8 8 #:I.,1=+/&.:*:"1 -"1/~ #:i.8
12 2 3

The 12 is the number of edges of a cube, the 2 is the number of ends
of each edge, and the 3 is the number of dimensions (which I will
think of as red, green, and blue).

If I could think up a good name, I'd probably stuff this in a variable
to make the rest of it easy.

Since this is getting long, I'll save the rest of it for another day
(unless someone else wants to take up the banner here?)

But, briefly, 255=3*85 so I if I make each edge 85 units long (which
becomes 86 values if I include the zero of the axis) I get a total of
256 values making up my cube diagonal. And, since we have a fair bit
of hardware designed around a 256 division scale for color rendering
that seemed like a nice choice.

Also, these edges are not arranged in any particular order, so I use a
convex hull algorithm (giftwrap) to arrange them in a form useful for
opengl rendering.

(And, yes, I am aware that some opengl hardware is... less than ideal?
in terms of color quality. That's not a priority issue for me, at this
stage of the game.)

So... time for lunch for me. And then I need to do something useful
for the people I work for. I may or may not come back to this bit of
code at a later time. Meanwhile, hopefully I will be able to have
provoked at least a little speculation about what I've written here
and what other mistakes I've made?

Thanks,

-- 
Raul
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to