POV-Ray : Newsgroups : povray.general : 2D function to 3D tube : Re: 2D function to 3D tube Server Time
19 May 2024 06:58:57 EDT (-0400)
  Re: 2D function to 3D tube  
From: Tor Olav Kristensen
Date: 25 Dec 2022 20:00:00
Message: <web.63a8f11a560d6168d6142c8889db30a9@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:
> "Tor Olav Kristensen" <tor### [at] TOBEREMOVEDgmailcom> wrote:
> > "Tor Olav Kristensen" <tor### [at] TOBEREMOVEDgmailcom> wrote:
> > > "Bald Eagle" <cre### [at] netscapenet> wrote:
> > > > "Droj" <803### [at] drojde> wrote:
> > > >
> > > > > > I will try to do some fine tuning as the heart curve still has an
inconsistency
> > > > > > where the dip is.
>
>
> > > My suspicion is that this is caused by a problem with the Paramcalc
> > > macro in meshmaker.inc (The SimpleMesh macro in the code below does
> > > not seem to have this problem.)
> > >
> > > The code below also shows an alternative way to make the final
> > > functions for the "tube".
> > >...
> >
> > I see now that the SimpleMesh macro is a bit messy.
>
> I haven't gone through any of the edited mesh macro code yet, but did some
> simple mesh creation code of my own, and the problem was still in the
> calculation of that damned angle Phi.  It's not very well-behaved, and jumps
> around a lot, making adjacent sections of mesh "flip" through the central curve
> trace.
>
> I played around with it for quite a while, graphing the values of Phi, and
> finally came up with this:
>
> #macro Implicit_CalculatePhi (UU, I_Derivative)
>  #local Phi = -atan2 (I_Derivative (UU)*UU, abs (UU+E));
>  // correct for flipping around x=0
>  #local Phi = select ((Phi+pi/2), Phi+pi, Phi);
>  #local Phi = select (UU, -Phi, 0, Phi);
>
>  Phi
> #end
>
> It keeps Phi as a nice, continuous value between +/-pi
>
> So in the loops, instead of calculating Phi, just use:
> #local Phi = Implicit_CalculatePhi (UU, I_Derivative);
>
> And that seems to have eliminated all of the problems I've noticed at x0 <= 0
> where there are mins and maxes in the curve.
>
> Hopefully this does the trick.   I have more curves to plot, and then need to
> adapt my macros to parametrics and then the polynomial curves.

Bill,

I'm worried that maybe you are making things more complicated than they are.
That's because my tests indicate that atan2(DFnY(u), DFnX(u)) does a good job
calculating the angle of the tangent. One just have to add or subtract pi/2 to
get an angle pi/2 (90 degrees) away from the tangent direction (in the
XY-plane).

I'll try to explain...

If we, in order to simplify things, set the tube radius to 1 and pretend
that POV-Ray has 3D-vector valued functions, then the problem can be
solved like this:

X = function(u) { 16*pow(sin(u), 3) }
Y = function(u) { 13*cos(u) - 5*cos(2*u) - 2*cos(3*u) - cos(4*u) }

pCtr = function3d(u) { <X(u), Y(u), 0> }

d_X = function(u) { 48*pow(sin(u), 2)*cos(u) }
d_Y = function(u) { -13*sin(u) + 10*sin(2*u) + 6*sin(3*u) + 4*sin(4*u) }

vTangent = function3d(u) { <d_X(u), d_Y(u), 0> }

TangentAngle = function(u) { atan2(d_Y(u), d_X(u)) }

OrthAngle = function(u) { TangentAngle(u) + pi/2 } // or TangentAngle(u) - pi/2


We need two vectors that are orthogonal to the tangent of the curve,
that is orthogonal to each other and has unit length. Since this is
a 2D curve in an XY-plane, they can be created like this:

vOrth_1a = function3d(u) { <cos(OrthAngle(u)), sin(OrthAngle(u)), 0> }

vOrth_2 = function3d(u) { <0, 0, +1> }  // or <0, 0, -1>

All the points on the surface can now be calculated like this:

pSurface =
    function3d(u, v) {
        pCtr(u) +
        cos(v)*vOrth_1a(u) +
        sin(v)*vOrth_2(u)
    }
pSurface =
    function3d(u, v) {
        <X(u), Y(u), 0> +
        cos(v)*<cos(OrthAngle(u)), sin(OrthAngle(u)), 0> +
        sin(v)*<0, 0, 1>
    }
pSurface =
    function3d(u, v) {
        <X(u), Y(u), 0> +
        <cos(v)*cos(OrthAngle(u)), cos(v)*sin(OrthAngle(u)), 0> +
        <0, 0, sin(v)>
    }
pSurface =
    function3d(u, v) {
        <
            cos(v)*cos(OrthAngle(u)) + X(u),
            cos(v)*sin(OrthAngle(u)) + Y(u),
            sin(v)
        >
    }

Here's an alternative way of creating the first orthogonal vector:

vTangentNormalized =
    function3d(u) {
        <cos(TangentAngle(u)), sin(TangentAngle(u)), 0>
    }

vOrth_1b =
    function3d(u) {
        <-vTangentNormalized(u).y, +vTangentNormalized(u).x, 0>
        // or <+vTangentNormalized(u).y, -vTangentNormalized(u).x, 0>
    }
vOrth_1b =
    function3d(u) {
        <-sin(TangentAngle(u)), +cos(TangentAngle(u)), 0>
    }

Again the points on the surface can be calculated like this:

pSurface =
    function3d(u, v) {
        pCtr(u) +
        cos(v)*vOrth_1b(u) +
        sin(v)*vOrth_2(u)
    }
pSurface =
    function3d(u, v) {
        <X(u), Y(u), 0> +
        cos(v)*<-sin(TangentAngle(u)), +cos(TangentAngle(u)), 0> +
        sin(v)*<0, 0, 1>
    }
pSurface =
    function3d(u, v) {
        <X(u), Y(u), 0> +
        <cos(v)*-sin(TangentAngle(u)), cos(v)*+cos(TangentAngle(u)), 0> +
        <0, 0, sin(v)>
    }
pSurface =
    function3d(u, v) {
        <
            -cos(v)*sin(TangentAngle(u)) + X(u),
            +cos(v)*cos(TangentAngle(u)) + Y(u),
            sin(v)
        >
    }


The normalized tangent can also be calculated like this:

vTangentNormalized =
    function3d(u) {
        <d_X(u), d_Y(u), 0>/f_r(d_X(u), d_Y(u), 0)
    }

Now we have yet another way to create the first orthogonal vector:

vOrth_1c =
    function3d(u) {
        <-vTangentNormalized(u).y, +vTangentNormalized(u).x, 0>
        // or <+vTangentNormalized(u).y, -vTangentNormalized(u).x, 0>
    }
vOrth_1c =
    function3d(u) {
        <-d_Y(u), +d_X(u), 0>/f_r(d_X(u), d_Y(u), 0)
    }

The points on the surface can be calculated like this:

pSurface =
    function3d(u, v) {
        pCtr(u) +
        cos(v)*vOrth_1c(u) +
        sin(v)*vOrth_2(u)
    }
pSurface =
    function3d(u, v) {
        <X(u), Y(u), 0> +
        cos(v)*<-d_Y(u), +d_X(u), 0>/f_r(d_X(u), d_Y(u), 0) +
        sin(v)*<0, 0, 1>
    }
pSurface =
    function3d(u, v) {
        <X(u), Y(u), 0> +
        cos(v)*<-d_Y(u), +d_X(u), 0>/f_r(d_X(u), d_Y(u), 0) +
        <0, 0, sin(v)>
    }
pSurface =
    function3d(u, v) {
        <
            -cos(v)*d_Y(u)/f_r(d_X(u), d_Y(u), 0) + X(u),
            +cos(v)*d_X(u)/f_r(d_X(u), d_Y(u), 0) + Y(u),
            sin(v)
        >
    }

--
Tor Olav
http://subcube.com
https://github.com/t-o-k


Post a reply to this message

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