Normal vector of "orthogonal" fcurves

As a visualiser for speaker tools I’ve created a sound surface mapped in y direction to the baked frequency fcurves and in the x by a temp crossing fcurve to create a displacement map. It occurs to me I could also make an rgb normal map by crossing the tangent vector of the two fcurves.

Does anybody know any sneaky tricky ways to find the tangent vector of an fcurve point? Currently I can only think of using a limit to approx the derivate to get the gradient egx

f = frame
dx = 0.00001 #some small number
rise = fcurve.evaluate(f+dx) - fcurve.evaluate(f-dx)
run = 2dx

tangent = rise / run

Attached a quick pic of the surface.


why fcurves are “orthogonal” ?
this minimum way to get gradient is probably the simplest way

vaguely remermber there is the other method which may gives better precision using the secant instead
but check some math site for this !

very interesting that from this you can make a bluish normal map
any code example for this !

another way would be to pass you points into a splne to interpolate in between points and may be get better precision!
see script for loop tool

there is this site for 3D bezier derivatives

might be possible to adapt it for 3D

happy bl

i found a snippet for bezier curve derivative

# get nth derivative of order(len(verts)) bezier curve

def getDerivative(verts, t, nth):
    order = len(verts) - 1 - nth
    QVerts = []
    for i in range(nth):
        if QVerts:
            verts = QVerts
        derivVerts = []
        for i in range(len(verts)-1):
            derivVerts.append(verts[i+1] - verts[i])
        QVerts = derivVerts
    point = mathutils.Vector((0, 0, 0))
    for i, vert in enumerate(QVerts):
        point += binom(order, i) * math.pow(t, i) * math.pow(1-t, order-i) * vert
    deriv = point
    return deriv

might be usefull

happy bl

This is just off the top of my head but the fcurves are based on bezier curves. It seems to me that the lines traced between the control points define inherently define tangent lines to the curve.

Thanks for the tips, I’ve gone for the simple approach.

import bpy
from mathutils import Vector

# get the tangent of an fcurve
# use v.yxz for the crossing curves

def tangent_vector(fcurve, frame, df=0.00001):
    v1 = Vector((frame-df, fcurve.evaluate(frame-df),0))
    v2 = Vector((frame+df, fcurve.evaluate(frame+df),0))

    return (v2-v1).normalized()

a =['ConeAction']
fcurve = a.fcurves[0]
vn = tangent_vector(fcurve, 100)

This leads me to my next hassle. I’m going to have to interpolate (probably lerp) to get the tangent vectors for values between each of the sound curves. (baking a sound fcurve for each pixel width of an image == a lifetime.)