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
    The forum rollback caused push notifications and recent user data to malfunction. The problem will fix itself naturally within the next days. See the topic Broken Push Notifications for a more in detail explanation. You can fix this yourself by forcibly clearing your browser cache (for most browsers: CTRL + F5).

    Can't snap to Generator output spline

    Cinema 4D SDK
    r25 python windows
    2
    4
    630
    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.
    • M
      Madara
      last edited by

      Hi guys!
      I'm trying to create spline outline generator. All is going good, but the resulted spline is invisible for Snapping tool. Even after placing the result directly under the generator (InsertUnder(op)) . It is only working if I'll select the result spline.
      Is it something connected to generator cache?

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

        Hello @Madara ,

        Welcome to the Plugin Café forum and the Cinema 4D development community, it is great to have you with us!

        Getting Started

        Before creating your next postings, we would recommend making yourself accustomed with our Forum and Support Guidelines, as they line out details about the Maxon SDK Group support procedures. Of special importance are:

        • Support Procedures: Scope of Support: Lines out the things we will do and what we will not do.
        • Support Procedures: Confidential Data: Most questions should be accompanied by code but code cannot always be shared publicly. This section explains how to share code confidentially with Maxon.
        • Forum Structure and Features: Lines out how the forum works.
        • Structure of a Question: Lines out how to ask a good technical question. It is not mandatory to follow this exactly, but you should follow the idea of keeping things short and mentioning your primary question in a clear manner.

        About your First Question

        Without your code we cannot do much here, I would recommend having a look at our forum guidelines (as explained above). If I had to take a guess, I would say you are probably overwriting ObjectData.GetVirtualObjects instead of .GetContour or you are missing the OBJECT_ISSPLINE flag when calling RegisterObjectPlugin, causing either your object not being recognized as a spline or having a malformed cache.

        When you implement a spline using GetVirtualObjects, the cache of that object will be a SplineObject, or in other words the object itself won't be a spline. When you implement it via .GetContour, the cache will be a LineObject (which is the correct cache node type for a spline).

        If you got a bit confused by this, you could easily test this in the console by calling GetCache() on an instance of your plugin. In the example below I compare the cache of a Python generator object which returns a SplineObject (which would be an example for such faux spline implemented using .GetVirtualObjects) and a SplineObject. Although they might look identical in the viewport, they are not the same under the hood.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • M
          Madara
          last edited by Madara

          Hi @ferdinand !

          Thank you for your response. It has to be the issue then. Is it possible to convert SplineObject to LineObject somehow?
          Here's my code so far:

          def main():
              parent = c4d.BaseObject(c4d.Onull)
              distance= op[c4d.ID_USERDATA,10]
              custom_distance=op[c4d.ID_USERDATA,1]
              link=op[c4d.ID_USERDATA,5]
              spline_color=op[c4d.ID_USERDATA,9]
              outline_only=op[c4d.ID_USERDATA,2]
              hide_input=op[c4d.ID_USERDATA,3]
              outline_color=op[c4d.ID_USERDATA,8]
              final_distance=5
              if distance == 0 :
                  final_distance=5
              elif distance == 1 :
                  final_distance=8
              elif distance==2:
                  final_distance=custom_distance
              link_clone = link.GetClone()
          
              connect_obj = c4d.BaseObject(c4d.Oconnector)
              link_clone.InsertUnder(connect_obj)
          
              if link_clone: #Parametric object
                  pobj   = u.SendModelingCommand(
                      command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                      list    = [connect_obj],
                      mode    = c4d.MODELINGCOMMANDMODE_ALL,
                      doc     = op.GetMain())
                  connect_obj = pobj[0]
          
              if outline_only:
                  bc = c4d.BaseContainer()
                  settings = c4d.BaseContainer()  # Settings
          
                  settings[c4d.MDATA_SPLINE_OUTLINE] = final_distance      # Distance
                  settings[c4d.MDATA_SPLINE_OUTLINESEPARATE] = True #Crée un nouvel objet
          
          
                  offspline = u.SendModelingCommand(
                      c4d.MCOMMAND_SPLINE_CREATEOUTLINE,
                      [connect_obj],
                      c4d.MODELINGCOMMANDMODE_ALL,
                      bc=settings,
                      doc=doc)
          
                  if offspline :
          
                      offspline[0].InsertUnder(parent)
                      offspline[0][c4d.ID_BASEOBJECT_USECOLOR] = 2  # Use Object ColorSpline
                      offspline[0][c4d.ID_BASELIST_ICON_COLORIZE_MODE]=2
                      offspline[0][c4d.ID_BASEOBJECT_COLOR] = outline_color  # Red Color
                      # Convert the spline to a line (edges) using a Modeling Command
                  
                  return offspline[0]
              if not outline_only:
                  #settings[c4d.MDATA_SPLINE_OUTLINESEPARATE] = True #Crée un nouvel objet
                  #connect_obj = c4d.BaseObject(c4d.Oconnector)
                  bc = c4d.BaseContainer()
                  bc.SetData(c4d.MDATA_SPLINE_OUTLINE, final_distance)
                  offspline = u.SendModelingCommand(
                      c4d.MCOMMAND_SPLINE_CREATEOUTLINE,
                      [connect_obj],
                      c4d.MODELINGCOMMANDMODE_ALL,
                      bc)
          
          
                  return connect_obj.GetClone()
          

          I'm inputting a null with multiple splines as children, then I put it under Connect object, simplify it, run outline command and get the result.

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

            Hey @Madara,

            in short, a Python generator object is not meant to generate splines. You can collapse the cache of your constructed spline and return its LineObject cache instead of the spline itself. For an example, see [1]. In your case that would be connect_obj. This will work in the sense that the generator cache will be then like a SplineObject cache and when you 'Current State to Object' your generator, it will behave like a spline and give you the interpolated editable linear spline and not a spline generator.

            However, spline snapping not only inspects caches, but also checks if OBJECT_ISSPLINE is true. So, you cannot bamboozle it by faking a SplineObject cache. You will have to implement a proper spline plugin for what you want to do, as you can overwrite there GetContour

            Cheers,
            Ferdinand

            PS: Your code contains multiple elements that can crash Cinema 4D and/or corrupt the loaded document. Specifically, these sections:

            
                if link_clone: #Parametric object
                    pobj   = u.SendModelingCommand(
                        command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                        list    = [connect_obj],
                        mode    = c4d.MODELINGCOMMANDMODE_ALL,
                        doc     = op.GetMain())
                    connect_obj = pobj[0]
            
            ...
            
                    offspline = u.SendModelingCommand(
                        c4d.MCOMMAND_SPLINE_CREATEOUTLINE,
                        [connect_obj],
                        c4d.MODELINGCOMMANDMODE_ALL,
                        bc=settings,
                        doc=doc)
            

            A Python generator's main() function is subject to the threading restrictions of Cinema 4D because it is just a wrapper for ObjectData.GetVirtualObjects. Executing SendModelingCommand in a threaded context is fine, but you cannot do it on the active document (both doc and op.GetDocument() are the active document). This is here even worsened by the fact that that the objects in list are not actually part of the document you pass as doc.

            To circumvent that you must create your own document just as I have in [1] with temp. Find a more detailed example of that technique in smc_extrude_s26.py.


            [1]

            import c4d
            
            op: c4d.BaseObject # The Python generator object.
            
            def main() -> c4d.BaseObject:
                """
                """
                # A user data Boolean to toggle collapsing the cache of this generator.
                collapse: bool  = op[c4d.ID_USERDATA, 1]
                spline: c4d.BaseObject = c4d.BaseObject(c4d.Osplinecircle)
                if not spline:
                    return c4d.BaseObject(c4d.Onull)
                
                # Just return the circle spline itself when #collapse is false.
                if not collapse:
                    return spline
                
                # Otherwise grab the LineObject cache of the spline and return a copy of it.
                temp: c4d.documents.BaseDocument = c4d.documents.BaseDocument()
                temp.InsertObject(spline)
            
                temp.ExecutePasses(c4d.threading.GeGetCurrentThread(), False, False, True, c4d.BUILDFLAGS_NONE)
                cache: c4d.LineObject | None = spline.GetCache()
            
                if not isinstance(cache, c4d.LineObject):
                    return c4d.BaseObject(c4d.Onull)
                
                return cache.GetClone(c4d.COPYFLAGS_NONE)
            

            MAXON SDK Specialist
            developers.maxon.net

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