POV-Ray : Newsgroups : povray.advanced-users : [Long] Points on a sphere? Not really. Server Time
25 Nov 2024 21:31:40 EST (-0500)
  [Long] Points on a sphere? Not really. (Message 1 to 9 of 9)  
From: Deaken
Subject: [Long] Points on a sphere? Not really.
Date: 16 Jan 2002 06:16:22
Message: <3C45612B.22351095@sw-tech.com>
A few things by way of introduction:

I'm not an advanced user, but it was suggested that this problem belongs
here.

I know that this problem has already been solved.  I know that it's
amazingly inefficient to do this as a macro instead of just importing
the points.  Neither of those, however, are the real issue anymore.

The real issue is that I am trying to convert spherepoints.c to a macro,
and I keep failing.  Well, actually, it works, it just gives different
results than I expect.  I would like someone with more skill than I at
SDL (or perhaps C, since neither are my "native language") to explain
where I am going astray in the conversion.  This strikes me as a useful
skill to have, and when something this simple is beyond my grasp, well,
I'd like to understand why, and try to fix it.

I've trimmed this down as much as I could.  Please forgive the size.

Um, if word-wrapping kills the formatting, please assume that it is
correct in the source files.

The source code to spherepoints.c can be found at
<URL:http://astronomy.swin.edu.au/pbourke/geometry/spherepoints/>.  I
have made the following minor changes, which should be obvious to place.

   /* Create the initial random cloud */
/*   for (i=0;i<n;i++) { */
       p[0].x = (0.2);
       p[0].y = (0.3);
       p[0].z = (0.5);
       Normalise(&p[0],r);
       p[1].x = (0.8);
       p[1].y = (0.1);
       p[1].z = (0.2);
       Normalise(&p[1],r);
       p[2].x = (0.0);
       p[2].y = (0.4);
       p[2].z = (0.7);
       Normalise(&p[2],r);
       p[3].x = (0.9);
       p[3].y = (0.2);
       p[3].z = (0.5);
       Normalise(&p[3],r);
/*    } */

[...]

    /* Write out the points in your favorite format */
    for (i=0;i<n;i++) {
      printf("#declare X%d = <%f,%f,%f>;\n",
       i,
       p[i].z, p[i].y, p[i].x
      );
    }
/* xyz xzy yxz yzx zxy zyx */

Here is my faulty macro.

#declare MovePercent = 1;
// This will be changed to 5% once it works, to speed up the macro a
bit.
#declare PlusElem = 1 + ( MovePercent / 100 );
#declare MinusElem = ( MovePercent / 100 );
#macro Normalize ( Vector )
  Vector / vlength ( Vector )
#end
#macro MyThing ( NumDots, Iters )
  #declare DotsArray = array[NumDots]
//  #declare Loop = 0;
//  #while ( Loop < NumDots )
//    #declare DotsArray[Loop] = Normalize (
<(rand(R1)*2)-1,(rand(R1)*2)-1,(rand(R1)*2)-1> );
//    #declare Loop = Loop + 1;
//  #end
  #declare DotsArray[0] = Normalize ( <0.2, 0.3, 0.5> );
  #declare DotsArray[1] = Normalize ( <0.8, 0.1, 0.2> );
  #declare DotsArray[2] = Normalize ( <0.0, 0.4, 0.7> );
  #declare DotsArray[3] = Normalize ( <0.9, 0.2, 0.5> );
  #declare Loop = 0;
  #while ( Loop < Iters )
    #declare MinP1 = 0;
    #declare MinP2 = 1;
    #declare MinD = vlength ( DotsArray[MinP1] - DotsArray[MinP2] );
    #declare MaxD = MinD;
    #declare SubLoopI = 0;
    #while ( SubLoopI < ( NumDots - 1 ) )
      #declare SubLoopJ = ( SubLoopI + 1 );
      #while ( SubLoopJ < NumDots )
        #declare CheckD = vlength ( DotsArray[SubLoopI] -
DotsArray[SubLoopJ] );
        #if ( CheckD < MinD )
          #declare MinD = CheckD;
          #declare MinP1 = SubLoopI;
          #declare MinP2 = SubLoopJ;
        #end
        #if ( CheckD > MaxD )
          #declare MaxD = CheckD;
        #end
        #declare SubLoopJ = ( SubLoopJ + 1 );
      #end
      #declare SubLoopI = ( SubLoopI + 1 );
    #end
    #declare P1 = DotsArray[MinP1];
    #declare P2 = DotsArray[MinP2];
    #declare DotsArray[MinP2] = Normalize (
      (
        <
          ( DotsArray[MinP1].x + PlusElem ) * ( DotsArray[MinP2].x -
DotsArray[MinP1].x ),
          ( DotsArray[MinP1].y + PlusElem ) * ( DotsArray[MinP2].y -
DotsArray[MinP1].y ),
          ( DotsArray[MinP1].z + PlusElem ) * ( DotsArray[MinP2].z -
DotsArray[MinP1].z ),
        >
      )
    );
    #declare DotsArray[MinP1] = Normalize (
      (
        <
          ( DotsArray[MinP1].x - MinusElem ) * ( DotsArray[MinP2].x -
DotsArray[MinP1].x ),
          ( DotsArray[MinP1].y - MinusElem ) * ( DotsArray[MinP2].y -
DotsArray[MinP1].y ),
          ( DotsArray[MinP1].z - MinusElem ) * ( DotsArray[MinP2].z -
DotsArray[MinP1].z ),
        >
      )
    );
    #declare Loop = Loop + 1;
  #end
  union {
    sphere {
      <0,0,0>, 1
      texture { pigment { color rgbt <0.7, 1, 0.7, 0.8+0.15> } }
    }
    #declare Loop = 0;
    #while ( Loop < NumDots )
      sphere {
        DotsArray[Loop]*0.9825,
        0.025
        texture {
          pigment {
            color rgbt <0, 1, 0, 0.5>
          }
        }
      }
      #declare Loop = Loop + 1;
    #end
  }
#end

I then do this:

#declare R1 = seed ( 2 );
object { MyThing ( 4, 10000 ) }
// This is the output from spherepoints
#declare X0 = <0.661471,-0.572393,0.484585>;
#declare X1 = <-0.910131,-0.285771,0.299995>;
#declare X2 = <0.152255,0.950505,0.270848>;
#declare X3 = <0.089845,-0.084676,-0.992350>;
#declare Test4_10K = union {
  cylinder { X0, X1, 0.01 }
  cylinder { X0, X2, 0.01 }
  cylinder { X0, X3, 0.01 }
  cylinder { X1, X2, 0.01 }
  cylinder { X1, X3, 0.01 }
  cylinder { X2, X3, 0.01 }
}
object { Test4_10K }

Yes, I've tried all possible permutations of X, Y and Z coordinates in
the spherepoints output.  I invoke the program as "./spherepoints 4 1
10000".

I thought the problem might be in the multi-line DotsArray[MinP2] (and
MinP1) statements, but I've tried many things there, and none of them
have worked.

The person for whom I offered to do this has pretty much accepted the
idea that it would be "better", if less "elegant", to use the output of
spherepoints in a .inc file, instead of running a 40-hour macro, but
this has moved from a specific problem to a general one, in my opinion. 
Any pointers would be gratefully accepted.

Thank you.

Deaken


Post a reply to this message

From: Warp
Subject: Re: [Long] Points on a sphere? Not really.
Date: 16 Jan 2002 07:05:12
Message: <3c456c78@news.povray.org>
Deaken <dwy### [at] sw-techcom> wrote:
: Well, actually, it works, it just gives different results than I expect.

:    /* Create the initial random cloud */

  Well, could that be the answer?

-- 
#macro M(A,N,D,L)plane{-z,-9pigment{mandel L*9translate N color_map{[0rgb x]
[1rgb 9]}scale<D,D*3D>*1e3}rotate y*A*8}#end M(-3<1.206434.28623>70,7)M(
-1<.7438.1795>1,20)M(1<.77595.13699>30,20)M(3<.75923.07145>80,99)// - Warp -


Post a reply to this message

From: Deaken
Subject: Re: [Long] Points on a sphere? Not really.
Date: 16 Jan 2002 08:27:26
Message: <3C457FE2.A613619E@sw-tech.com>
Warp wrote:
> 
> Deaken <dwy### [at] sw-techcom> wrote:
> : Well, actually, it works, it just gives different results than I expect.
> 
> :    /* Create the initial random cloud */
> 
>   Well, could that be the answer?

No, since that routine is actually commented out in what I posted, and I
assign the initial 4 points to <0.2, 0.3, 0.5>, <0.8, 0.1, 0.2>, <0.0,
0.4, 0.7>, <0.9, 0.2, 0.5> (before normalization, that is) in both the C
and the SDL versions.

Deaken


Post a reply to this message

From: Tor Olav Kristensen
Subject: Re: [Long] Points on a sphere? Not really.
Date: 16 Jan 2002 20:20:32
Message: <3C462654.32935357@hotmail.com>
Deaken wrote:
> 
>     #declare DotsArray[MinP2] = Normalize (
>       (
>         <
>           ( DotsArray[MinP1].x + PlusElem ) * ( DotsArray[MinP2].x -
> DotsArray[MinP1].x ),
>           ( DotsArray[MinP1].y + PlusElem ) * ( DotsArray[MinP2].y -
> DotsArray[MinP1].y ),
>           ( DotsArray[MinP1].z + PlusElem ) * ( DotsArray[MinP2].z -
> DotsArray[MinP1].z ),
>         >
>       )
>     );
>     #declare DotsArray[MinP1] = Normalize (
>       (
>         <
>           ( DotsArray[MinP1].x - MinusElem ) * ( DotsArray[MinP2].x -
> DotsArray[MinP1].x ),
>           ( DotsArray[MinP1].y - MinusElem ) * ( DotsArray[MinP2].y -
> DotsArray[MinP1].y ),
>           ( DotsArray[MinP1].z - MinusElem ) * ( DotsArray[MinP2].z -
> DotsArray[MinP1].z ),
>         >
>       )
>     );
>     #declare Loop = Loop + 1;
>   #end
>   union {
>     sphere {
>       <0,0,0>, 1
>       texture { pigment { color rgbt <0.7, 1, 0.7, 0.8+0.15> } }
>     }
>     #declare Loop = 0;
>     #while ( Loop < NumDots )
>       sphere {
>         DotsArray[Loop]*0.9825,
>         0.025
>         texture {
>           pigment {
>             color rgbt <0, 1, 0, 0.5>
>           }
>         }
>       }
>       #declare Loop = Loop + 1;
>     #end
>   }
> #end
>...
 
>...
> I thought the problem might be in the multi-line DotsArray[MinP2] (and
> MinP1) statements, but I've tried many things there, and none of them
> have worked.
>...

Here's a reformatted version of what you wrote:

#declare DotsArray[MinP2] =
Normalize(
  (
    <
      (DotsArray[MinP1].x + PlusElem)*(DotsArray[MinP2].x - DotsArray[MinP1].x),
      (DotsArray[MinP1].y + PlusElem)*(DotsArray[MinP2].y - DotsArray[MinP1].y),
      (DotsArray[MinP1].z + PlusElem)*(DotsArray[MinP2].z - DotsArray[MinP1].z),
    >
  )
);

Above there's one level of parentheses more
than necessary:

Normalize((  ));

And the last comma should not be there.

You can replace your Normalize() macro with
a call to the built in vnormalize() operator.

And the parentheses in these three expressions
were not present in Paul Bourke's code:

(DotsArray[MinP1].x + PlusElem)
(DotsArray[MinP1].y + PlusElem)
(DotsArray[MinP1].z + PlusElem)

(Will lead to a serious calculation error)

Also note that all the declarations of the
variables that are only being used within
your macro should be declared with the
#local directive.

So the corrected code should be:

#local DotsArray[MinP2] =
vnormalize(
  <
    DotsArray[MinP1].x + PlusElem*(DotsArray[MinP2].x - DotsArray[MinP1].x),
    DotsArray[MinP1].y + PlusElem*(DotsArray[MinP2].y - DotsArray[MinP1].y),
    DotsArray[MinP1].z + PlusElem*(DotsArray[MinP2].z - DotsArray[MinP1].z)
  >
);

Which can be rewritten like this:

#local DotsArray[MinP2] =
vnormalize(
  <
    DotsArray[MinP1].x,
    DotsArray[MinP1].y,
    DotsArray[MinP1].z
  >
  + PlusElem*
  <
    DotsArray[MinP2].x - DotsArray[MinP1].x,
    DotsArray[MinP2].y - DotsArray[MinP1].y,
    DotsArray[MinP2].z - DotsArray[MinP1].z
  >
);

And further:

#local DotsArray[MinP2] =
vnormalize(
  <DotsArray[MinP1].x, DotsArray[MinP1].y, DotsArray[MinP1].z>
  + PlusElem*
  (
    <DotsArray[MinP2].x, DotsArray[MinP2].y, DotsArray[MinP2].z>
    -
    <DotsArray[MinP1].x, DotsArray[MinP1].y, DotsArray[MinP1].z>
  )
);

All the way to this:

#local DotsArray[MinP2] =
vnormalize(
  DotsArray[MinP1] + PlusElem*(DotsArray[MinP2] - DotsArray[MinP1])
);

Doing the same with your second declaration above:

#local DotsArray[MinP1] =
vnormalize(
  DotsArray[MinP1] - MinusElem*(DotsArray[MinP2] - DotsArray[MinP1])
);


Also have a look at this:

p[p1] = p1 - 0.01*(p2 - p1)

p[p2] = p1 + 1.01*(p2 - p1)
p[p2] = p1 + (1.01*p2 - 1.01*p1)
p[p2] = p1 + 1.01*p2 - 1.01*p1
p[p2] = 1.01*p2 - 0.01*p1
p[p2] = p2 + 0.01*p2 - 0.01*p1
p[p2] = p2 + 0.01*(p2 - p1)

This means that you don't have to use two
different constants for the percent amount to
move the points.

I.e. you can replace both the PlusElem and the
MinusElem constants with e.g. MovePercent if
you rewrite the expression for DotsArray[MinP2]
a little.

And since both expressions use a common sub
expression and to make things easier to
understand, you could pre-calculate this
common expression and put it in a separate
variable; vDir.

Now we have this:

#local MovePercent = 5/100;
#local vDir = DotsArray[MinP2] - DotsArray[MinP1];
#local DotsArray[MinP1] = vnormalize(DotsArray[MinP1] - MovePercent*vDir);
#local DotsArray[MinP2] = vnormalize(DotsArray[MinP2] + MovePercent*vDir);


I hope this helped a little.
(But note that I have not tested any of the code above.)


Tor Olav


Post a reply to this message

From: Tor Olav Kristensen
Subject: Re: [Long] Points on a sphere? Not really.
Date: 16 Jan 2002 20:30:39
Message: <3C4628BF.DE96D9FD@hotmail.com>
Tor Olav Kristensen wrote:

>...
> Now we have this:
> 
> #local MovePercent = 5/100;
> #local vDir = DotsArray[MinP2] - DotsArray[MinP1];
> #local DotsArray[MinP1] = vnormalize(DotsArray[MinP1] - MovePercent*vDir);
> #local DotsArray[MinP2] = vnormalize(DotsArray[MinP2] + MovePercent*vDir);
>...

Since you declared both P1 and P2 earlier in your
code, you can use this code instead

#local MovePercent = 5/100;
#local P1 = DotsArray[MinP1];
#local P2 = DotsArray[MinP2];
#local vDir = P2 - P1;
#local DotsArray[MinP1] = vnormalize(P1 - MovePercent*vDir);
#local DotsArray[MinP2] = vnormalize(P2 + MovePercent*vDir);


Tor Olav


Post a reply to this message

From: Deaken
Subject: Re: [Long] Points on a sphere? Not really.
Date: 16 Jan 2002 22:38:17
Message: <3C46474D.605E55C0@sw-tech.com>
Tor Olav Kristensen wrote: 

[I've snipped the cosmetic and newbie errors (too many parens, etc.)

Also, I had #local instead of #declare originally, then thought that
that might be the problem, replaced them, saw no difference, never
bothered to change them back.]

> And the parentheses in these three expressions
> were not present in Paul Bourke's code:
> 
> (DotsArray[MinP1].x + PlusElem)
> (DotsArray[MinP1].y + PlusElem)
> (DotsArray[MinP1].z + PlusElem)
> 
> (Will lead to a serious calculation error)

Ah.  Operator precedence.  Thank you SO much, Tor.

> This means that you don't have to use two
> different constants for the percent amount to
> move the points.
> 
> I.e. you can replace both the PlusElem and the
> MinusElem constants with e.g. MovePercent if
> you rewrite the expression for DotsArray[MinP2]
> a little.

I did that for "clarity" (FSVO).  This was intended to be for someone
only slightly less experienced than I am (because it's only possible to
be SLIGHTLY less experienced than I am) to read.

> I hope this helped a little.
> (But note that I have not tested any of the code above.)

I haven't tested it either (not able to quite yet), but that's the only
thing I didn't check several dozen times.  I'm sure that's it.  Thank
you once again.

Deaken


Post a reply to this message

From: Deaken
Subject: Re: [Long] Points on a sphere? Not really.
Date: 17 Jan 2002 19:01:29
Message: <3C476601.B36BFAD8@sw-tech.com>
Deaken wrote:
 
[Tor Olav Kristensen explained where my C->SDL translations failed]

> I haven't tested it either (not able to quite yet), but that's the only
> thing I didn't check several dozen times.  I'm sure that's it.  Thank
> you once again.

Well, I just tested it.  It doesn't give the same result as the C
program does, but since it gives acceptable results, I'm going to mark
it as working and move on.  Thanks again, Tor.

Next time I think that I will pick a simpler algorithm to try to
convert.  Feh.

Deaken


Post a reply to this message

From: Tor Olav Kristensen
Subject: Re: [Long] Points on a sphere? Not really.
Date: 17 Jan 2002 19:06:55
Message: <3C4766AB.DF2B531E@hotmail.com>
Deaken wrote:
> 
> Deaken wrote:
> 
> [Tor Olav Kristensen explained where my C->SDL translations failed]
> 
> > I haven't tested it either (not able to quite yet), but that's the only
> > thing I didn't check several dozen times.  I'm sure that's it.  Thank
> > you once again.
> 
> Well, I just tested it.  It doesn't give the same result as the C
> program does, but since it gives acceptable results, I'm going to mark
> it as working and move on.  Thanks again, Tor.

You're welcome Deaken.

If you like I can have a second
look at your code later.

If so, then just post your code as
it is now, and then I'll look at it
when I have some spare time.


Tor Olav


Post a reply to this message

From: Deaken
Subject: Re: [Long] Points on a sphere? Not really.
Date: 17 Jan 2002 19:17:44
Message: <3C4769D1.2B09D6C6@sw-tech.com>
Tor Olav Kristensen wrote:
> 
> Deaken wrote:
> >
> > Well, I just tested it.  It doesn't give the same result as the C
> > program does, but since it gives acceptable results, I'm going to mark
> > it as working and move on.  Thanks again, Tor.
> 
> You're welcome Deaken.
> 
> If you like I can have a second
> look at your code later.

No thanks.  Since it works (and is slow), and since a C program is much
faster, I'm just going to make the C prog spit out an include file, so
that the image doesn't take days to parse.

Deaken


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.