Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Set Tangnet of Spline

    Cinema 4D SDK
    python
    2
    3
    551
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • gheyretG
      gheyret
      last edited by

      Hi everyone!
      I have recently been learning some basics of linear algebra.
      In order to verify my learning results, I created a Bezier spline Generator with Python Generator.
      But when I set the tangents of the spline, something confused me.
      When I moved the point of the spline, the left and right handles of the tangent would switch positions, or would they flip 180 degrees? I don't quite understand what's going on here.

      20240914_170405.gif

      And there is my test code and Scene file:

      import c4d
      import math
      
      def main() -> c4d.BaseObject:
          null = c4d.BaseObject(c4d.Onull)
      
          a = op.GetDown()
          b = a.GetNext()
          c = b.GetNext()
      
          obj = b.GetClone(0)
          obj[c4d.NULLOBJECT_RADIUS] = 5
          obj[c4d.ID_BASEOBJECT_USECOLOR] = 2
          obj[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(1,0,0)
          obj2 = obj.GetClone(0)
          obj2[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(0,1,0)
      
          a_pos_local = ~b.GetMg() * a.GetMg().off
          a_polar_angle = math.atan2(a_pos_local.y, a_pos_local.x)
          a_length = a_pos_local.GetLength()
      
          b_pos_local = ~b.GetMg() * c.GetMg().off
          b_polar_angle = math.atan2(b_pos_local.y, b_pos_local.x)
          b_length = b_pos_local.GetLength()
      
          polar = (a_polar_angle + b_polar_angle)/2 + (math.pi / 2)
          leng = (a_length + b_length)/2
          x = leng * math.cos(polar)
          y = leng * math.sin(polar)
          vec = c4d.Vector(x,y)
      
      
          move_vec1 =  vec.GetNormalized() * op[c4d.ID_USERDATA,1]
          m1 = ~op.GetMg() * b.GetMg() * c4d.utils.MatrixMove(move_vec1)
          m2 = ~op.GetMg() * b.GetMg() * c4d.utils.MatrixMove(-move_vec1)
      
          obj.SetMg(m1)
          obj2.SetMg(m2)
      
          obj.InsertUnder(null)
          obj2.InsertUnder(null)
          
          spline = c4d.SplineObject(3, c4d.SPLINETYPE_BEZIER)
          spline.SetPoint(0, a.GetMg().off)
          spline.SetPoint(1, b.GetMg().off)
          spline.SetPoint(2, c.GetMg().off)
          
          vl = ~b.GetMg() * obj.GetMg().off
          vr = ~b.GetMg() * obj2.GetMg().off
          spline.SetTangent(1, vl, vr)
          
          spline.InsertUnder(null)
      
          return null
      

      tangent.c4d

      www.boghma.com

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @gheyret
        last edited by ferdinand

        Hey @gheyret,

        thank you for reaching out to us. Please note that both questions about mathematical concepts and debugging user code are out of scope of support, as declared in our Support Procedures.

        Linear algebra is a mathematical subject which is famous for being overloaded with other subjects, probably because it has become so popular. So, people can mean a lot when they say "linear algebra", a popular misnaming is for example to treat it as synonymous with statistics, a.k.a., machine learning, because it is there being used a lot. But at its heart linear algebra is just the sub-section of vector/matrix algebra which limits itself to the name giving linear combinations, sometimes also labeled as linear transforms. A linear combination is just the sum of an arbitrary set of vectors, each multiplied by a scalar (basically a fancy word for a number), e.g., 4x + 9y + -2.2z or 22x + z are both examples of linear combinations, where x, y, and z are vectors.

        In computer graphics linear combinations/algebra are popular because among other things they are very useful to express a transform, a bundle of an offset, an orientation and a scale. A 'matrix/transform' does nothing other than encoding the linear combination M(p)=off + p.x*x + p.y*y + p.z*z for a matrix M transforming the point P and the frame x, y, z of that matrix M. Linear algebra then usually also means writing that linear combination off + p.x*x + p.y*y + p.z*z in a matrix form which is more convenient for multiple reasons.

        Your code is mostly about trigonometry, the subject of mathematics which is all about the relation of the right triangle to the circle. Which then manifest as the central trigonometric identities sine, cosine, and tangent which due to their intimate relation with the circle are also called circle functions. This has nothing to do with linear algebra, but you need trigonometry to construct the basis (or as I prefer to say: frame) of a vector space. This is then sometimes called a rotation matrix, but that is a bit misleading since all transforms/linear combinations also encode an orientation/rotation. It is just that some transforms encode uninteresting oreintations such as (0°, 0°, 0°) . But the point of transforms is exactly not to do this, as trigonometry although somewhat simple school math can prove tricky in detail, and more important on the computer: computing the sine and cosine of things is very slow while using a (linear) transform which encodes that rotation is very fast. So, I do not want to stop your appetite for coding adventures, I am all for it, go ahead and explore! But you should be aware that what you are doing there is mostly trigonometry.

        About your problem at hand

        Due to the fact that the sum of the angles of a triangle is 180° (at least in Euclidean space), the angle/circle measuring/describing capabilities of the scircle functions sine, cosine, etc. is limited to 180°. After that value they just flip over, so 181° is just 1° for them (π radians is 180°, after that you need a multiple of π to express an angle in degree). You can exhibit this indirectly when you print out your a_polar_angle and b_polar_angle, as they simply flip over at certain points, suddenly go from the positive into the negative due that limit (at least I think that is what is happening there in your code).

        -2.995054571067229 0.5746922011297894
        -2.995054571067229 0.5746922011297894
        -3.0671200894559045 0.5746922011297894
        -3.117816186863078 0.5746922011297894
        # The value flips here suddenly, your output is not continuous anymore, because π did 'overflow'
        3.129067398903298 0.5746922011297894
        3.0422583006849884 0.5746922011297894
        2.9745193433216155 0.5746922011297894
        2.939439875027449 0.5746922011297894
        2.9082912851108667 0.5746922011297894
        

        In the end I cannot debug all your code for you as this is out of scope of support and I do not truly understand what you are doing there exactly (one of the reasons why such things are out of scope of support). In general I would advise against doing the trigonometry yourself (use something like sine, cosine, or tan in your code). It is slow and even when somewhat comfortable with the math behind it, it is easy to make mistakes. Transforms (a.k.a linear combinations/transforms) as expressed in API such as c4d exist exactly so that you do not have to touch the trigonometry yourself.

        As I said, I do not truly understand what you are trying to do here in the first place. If you just want to place the two tangent handles in relation to your two input objects a and c, you can just do this:

        
        n: c4d.Vector = ~(c - a) # Get the normalized vector pointing from a to b.
        t0: c4d.Vector = b + (n * -tangentLength) # The position of the left tangent.
        t1: c4d.Vector = b + (n * tangentLength) # The position of the right tangent.
        

        But your code does something different with a non-linear rotation behavior, where for small angles (e.g., a ° b <= 15°) the relation above holds true, but for larger angles (e.g., a ° b >= 90°) not anymore. I am not sure if that is intentional. If you just want to align the tangent handles of a spline, you can look at this thread, I once showed there what I would consider a clean algebraic solution to the problem (no angle measuring required at all).

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        gheyretG 1 Reply Last reply Reply Quote 0
        • gheyretG
          gheyret @ferdinand
          last edited by

          Hi @ferdinand !
          Sorry for late reply, and thank you very much for your detailed and thorough explanation, and for taking the time to explain the relationship between linear algebra and trigonometry in the context of computer graphics and transformations.
          As a beginner, all I want to do here is to practice as much as I can with the knowledge I've learned, and I apologize if I didn't explain clearly.
          Yes, in the code I want to implement is placing two tangent handle relative to the two input objects a and c.
          Compared to calculating with trigonometric functions, your suggestion seems more straightforward and clear, and I never would have thought to use vectors to achieve this, I need to keep practicing.
          I will take the time to review the thread you mentioned.
          Thank you again for your support and guidance. Thank you very much for your insights!

          www.boghma.com

          1 Reply Last reply Reply Quote 0
          • First post
            Last post