Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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
    • Recent
    • Tags
    • Users
    • Register
    • Login

    Using the Bridge Tool

    Scheduled Pinned Locked Moved Cinema 4D SDK
    python
    9 Posts 2 Posters 116 Views 1 Watching
    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.
    • D Offline
      Dimitris_Derm.
      last edited by

      Hello, I'm trying to use the Bridge Tool with the SendModelingCommand but I'm having trouble as there are attributes I don't know how to use. Could someone explain to me what these are for ?

      MDATA_BRIDGE_ELEMENT1 = 1100, //LONG
      MDATA_BRIDGE_ELEMENT2 = 1101, //LONG
      MDATA_BRIDGE_ELEMENT3 = 1102, //LONG
      MDATA_BRIDGE_ELEMENT4 = 1103, //LONG
      MDATA_BRIDGE_OBJINDEX1 = 1104, //LINK
      MDATA_BRIDGE_OBJINDEX2 = 1105, //LINK
      MDATA_BRIDGE_OBJINDEX3 = 1106, //LINK
      MDATA_BRIDGE_OBJINDEX4 = 1107, //LINK
      MDATA_BRIDGE_DELETE = 1108, //BOOL
      MDATA_BRIDGE_ISO = 1109, //BOOL

      Also, given the type of elements I'm bridging and subsequently the modeling mode in which I will be using the Tool should I look out for specific things like the sequence of edges or points between the two parts to be connected ? Should I be treating Edge Selections like a sequence of point IDs or can I use them with their own IDs ?

      Thank you for your time.

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF Offline
        ferdinand @Dimitris_Derm.
        last edited by ferdinand

        Hey @Dimitris_Derm. ,

        Thank you for reaching out to us. The bridge tool in Cinema supports (in point mode) up to four objects as inputs. MDATA_BRIDGE_OBJINDEX1 to MDATA_BRIDGE_OBJINDEX4 are BaseLink parameters where you must link the PolygonObject instances you want to bridge. When you want the common case of bridging within one object, you set the same object for all four slots.

        MDATA_BRIDGE_ELEMENT1 to MDATA_BRIDGE_ELEMENT4 are then the element (e.g. point) indices to bridge (which can be scattered over multiple objects). They will be evaluated in relation to what you have set for the object indices.

        MDATA_BRIDGE_DELETE is "Delete Original Polygons" when you are bridging polygons in polygon mode. MDATA_BRIDGE_ISO seems to be related to SDS isoparms in the viewport, you can probably ignore it.

        // Only use case of MDATA_BRIDGE_ISO in our code base, very likely a dormant parameter.
        Bool BridgeTool::MouseInput(...)
        {
          // ...
          if (bd->GetEditState()& DISPLAYEDITSTATE::SDS)
            data.SetBool(MDATA_BRIDGE_ISO, true);
          else
            data.SetBool(MDATA_BRIDGE_ISO, false);
          // ...
        

        When bridging in edge mode, you likely will have to operate with half-edge indices, as for example described under GetEdgeS. I would personally either go for point or polygon mode bridging, as edges are a virtual construct which can be a pain in the *** to deal with in code.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • D Offline
          Dimitris_Derm.
          last edited by

          Oh ! we can bridge independent objects ? That simplifies things as I thought I would have to Connect+Delete first and then bridge...
          Thank you for the explanation of the attribute calls.

          1 Reply Last reply Reply Quote 0
          • D Offline
            Dimitris_Derm.
            last edited by Dimitris_Derm.

            @ferdinand I'm still having trouble with this.

            I'm trying to bridge polygon selections on a single merged object, but it keeps returning False.

            My setup:

            • Single polygon object (2 cylinders under a Connect, then Connect+Delete)
            • Two polygon selection tags with different names on the merged object
            • Polygon mode (MODELINGCOMMANDMODE_POLYGONSELECTION)

            All settings:

            python  settings[MDATA_BRIDGE_RESTRICT] = True
            settings[MDATA_BRIDGE_OBJINDEX1] = merged_obj
            settings[MDATA_BRIDGE_OBJINDEX2] = merged_obj
            settings[MDATA_BRIDGE_OBJINDEX3] = merged_obj
            settings[MDATA_BRIDGE_OBJINDEX4] = merged_obj
            settings[MDATA_BRIDGE_ELEMENT1] = 48  # First polygon of source selection
            settings[MDATA_BRIDGE_ELEMENT2] = 56  # Last polygon of source selection
            settings[MDATA_BRIDGE_ELEMENT3] = 19  # First polygon of target selection
            settings[MDATA_BRIDGE_ELEMENT4] = 30  # Last polygon of target selection
            //+ subdivision, tension, mode, etc.
            

            The bridge tool returns False. The selections are verified to exist on the object (9 polygons at indices 48-56, and 12 polygons at indices 19-30).

            Questions:

            • Do all MDATA_BRIDGE_OBJINDEX# need to be filled when bridging in polygon mode ?
            • Do I need to apply the selections to the active BaseSelect, or should they only be in tags?
            • Are there other required parameters for polygon mode ?
            • Does RESTRICT=True have any meaning when using the tool programmatically ?
            • If MDATA_BRIDGE_DELETE is "Keep Original Polygons" when bridging polygons then what is the MDATA_BRIDGE_KEEP_POLYGONS ?

            Thanks!

            ferdinandF 1 Reply Last reply Reply Quote 0
            • ferdinandF Offline
              ferdinand @Dimitris_Derm.
              last edited by

              Hey @Dimitris_Derm. ,

              please share complete code and a scene of what you are doing, otherwise I am guessing what you are trying to do. I assume you are trying to bridge to polygon islands, i.e., instead of distinct mesh elements in the destination and target, you have a group of polygons selected in both and then want to bridge by specifying a point index in the destination and target (which are an element of said polygon selections)?

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 0
              • D Offline
                Dimitris_Derm.
                last edited by

                @ferdinand

                At this point I have no idea what the difference between "Polygon Islands" and "Polygon Selections" is ....
                But yes, I have tried this with both two different objects and a single unified mesh of the two objects and didn't work. Exactly the same way I would do it manually as a user but this time I set polygon selections on the object and link them on the plugin generator to handle them.

                """
                Minimal example of trying to use ID_MODELING_BRIDGE_TOOL programmatically
                to bridge two polygon selections on a single merged object.
                
                SETUP:
                - Two cylinder objects with polygon selection tags
                - Each tag selects polygons on one end cap
                - We merge them with Connect, then try to bridge the selections
                
                PROBLEM:
                - With OBJINDEX1 only: C4D crashes
                - With OBJINDEX1 and OBJINDEX3: C4D crashes  
                - With all four OBJINDEX: Returns False (no crash, but doesn't work)
                """
                
                import c4d
                from c4d import utils
                
                def BridgePolygonSelections(doc):
                    """
                    Attempt to bridge two polygon selections on a merged object
                    """
                    
                    # Get two source objects with polygon selection tags
                    obj1 = doc.SearchObject("Cylinder")      # Has tag "Polygon Selection" with 9 polys selected
                    obj2 = doc.SearchObject("Cylinder 2")    # Has tag "Polygon Selection" with 12 polys selected
                    
                    if not obj1 or not obj2:
                        print("Objects not found")
                        return
                    
                    # Clone the objects
                    clone1 = obj1.GetClone()
                    clone2 = obj2.GetClone()
                    
                    # Get the polygon selection tags
                    tag1 = clone1.GetTag(c4d.Tpolygonselection)
                    tag2 = clone2.GetTag(c4d.Tpolygonselection)
                    
                    if not tag1 or not tag2:
                        print("Selection tags not found")
                        return
                    
                    # CRITICAL: Rename tags so Connect doesn't merge them into one
                    tag1.SetName("bridge_source")
                    tag2.SetName("bridge_target")
                    
                    # Extract polygon indices from original tags
                    source_indices = []
                    target_indices = []
                    
                    bs1 = tag1.GetBaseSelect()
                    bs2 = tag2.GetBaseSelect()
                    
                    for i in range(clone1.GetPolygonCount()):
                        if bs1.IsSelected(i):
                            source_indices.append(i)
                    
                    for i in range(clone2.GetPolygonCount()):
                        if bs2.IsSelected(i):
                            target_indices.append(i)
                    
                    print(f"Source: {len(source_indices)} polygons")
                    print(f"Target: {len(target_indices)} polygons")
                    
                    # Create temp document
                    temp_doc = c4d.documents.BaseDocument()
                    
                    # Create Connect object and insert clones under it
                    connect = c4d.BaseObject(1011010)
                    temp_doc.InsertObject(connect)
                    clone1.InsertUnder(connect)
                    clone2.InsertUnder(connect)
                    
                    # Execute passes to build Connect cache
                    temp_doc.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_NONE)
                    
                    # Make Connect editable to get merged polygon object
                    result = utils.SendModelingCommand(
                        command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                        list=[connect],
                        mode=c4d.MODELINGCOMMANDMODE_ALL,
                        doc=temp_doc
                    )
                    
                    if not result:
                        print("Failed to make Connect editable")
                        return
                    
                    merged_obj = result[0]
                    print(f"Merged object: {merged_obj.GetPolygonCount()} polygons")
                    
                    # Find the two selection tags on merged object
                    source_tag = None
                    target_tag = None
                    
                    tag = merged_obj.GetFirstTag()
                    while tag:
                        if tag.GetName() == "bridge_source":
                            source_tag = tag
                        elif tag.GetName() == "bridge_target":
                            target_tag = tag
                        tag = tag.GetNext()
                    
                    if not source_tag or not target_tag:
                        print("Tags not found on merged object")
                        return
                    
                    # Extract actual polygon indices from merged object's tags
                    merged_source = []
                    merged_target = []
                    
                    bs_src = source_tag.GetBaseSelect()
                    bs_tgt = target_tag.GetBaseSelect()
                    
                    for i in range(merged_obj.GetPolygonCount()):
                        if bs_src.IsSelected(i):
                            merged_source.append(i)
                        if bs_tgt.IsSelected(i):
                            merged_target.append(i)
                    
                    print(f"Merged source indices: {merged_source}")
                    print(f"Merged target indices: {merged_target}")
                    
                    # Build bridge settings
                    settings = c4d.BaseContainer()
                    settings[c4d.MDATA_BRIDGE_RESTRICT] = True
                    
                    # QUESTION: How to set OBJINDEX for polygon mode?
                    # Option 1: Only OBJINDEX1 (CRASHES C4D)
                    # settings[c4d.MDATA_BRIDGE_OBJINDEX1] = merged_obj
                    
                    # Option 2: OBJINDEX1 and OBJINDEX3 (CRASHES C4D)
                    settings[c4d.MDATA_BRIDGE_OBJINDEX1] = merged_obj
                    settings[c4d.MDATA_BRIDGE_OBJINDEX3] = merged_obj
                    
                    # Option 3: All four OBJINDEX (Returns False, doesn't crash)
                    # settings[c4d.MDATA_BRIDGE_OBJINDEX1] = merged_obj
                    # settings[c4d.MDATA_BRIDGE_OBJINDEX2] = merged_obj
                    # settings[c4d.MDATA_BRIDGE_OBJINDEX3] = merged_obj
                    # settings[c4d.MDATA_BRIDGE_OBJINDEX4] = merged_obj
                    
                    # ELEMENT parameters - first and last polygon of each selection
                    settings[c4d.MDATA_BRIDGE_ELEMENT1] = merged_source[0]   # 48
                    settings[c4d.MDATA_BRIDGE_ELEMENT2] = merged_source[-1]  # 56
                    settings[c4d.MDATA_BRIDGE_ELEMENT3] = merged_target[0]   # 19
                    settings[c4d.MDATA_BRIDGE_ELEMENT4] = merged_target[-1]  # 30
                    
                    # Other settings
                    settings[c4d.MDATA_BRIDGE_SUBDIVISION] = 0
                    settings[c4d.MDATA_BRIDGE_TENSION] = 0.0
                    settings[c4d.MDATA_BRIDGE_BOTH_MODE] = 0
                    
                    print(f"Executing bridge...")
                    
                    # Execute bridge
                    bridge_result = utils.SendModelingCommand(
                        command=c4d.ID_MODELING_BRIDGE_TOOL,
                        list=[merged_obj],
                        mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                        bc=settings,
                        doc=temp_doc
                    )
                    
                    print(f"Bridge result: {bridge_result}")
                    
                    if bridge_result:
                        print("SUCCESS!")
                    else:
                        print("Bridge returned False")
                
                # Run it
                if __name__ == '__main__':
                    doc = c4d.documents.GetActiveDocument()
                    BridgePolygonSelections(doc)
                

                I would post the full zip but I get a server error again... something must have broken on this forum with uploaded files as I had the same issue when trying to upload a screenshot

                ferdinandF 1 Reply Last reply Reply Quote 0
                • ferdinandF Offline
                  ferdinand @Dimitris_Derm.
                  last edited by ferdinand

                  Hey @Dimitris_Derm. ,

                  you should be able to upload things, it is at least working for me and other users. But we have a file size limit of 32 megabytes and only allow the file types: png jpg bmp c4d gif txt py pyp vdb zip mp4 webm cpp h pdf mov.

                  NodeBB sometimes also rejects GIFs and JPEGs when it thinks they contain a malicious payload but that should not happen for images sourced from an OS or reputable apps such as Photoshop, Gimp, InfraView, XnView, etc.

                  Your code contains some mistakes, and the question what you want to bridge (islands or elements) is still not clear to me, as you yourself do not seem to be quite sure. Since the case of bridging islands is not entirely trivial, and because SMC in general tends to be a hurdle for users, I decided to add a dedicated bridge tool SMC example to the SDK.

                  You can find the example here, it should cover you use case, since I go over both bridging distinct elements and bridging selection islands.

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 0
                  • D Offline
                    Dimitris_Derm.
                    last edited by Dimitris_Derm.

                    Thank you very much for the hands-on example @ferdinand !

                    About "Islands" and "selections" terms.

                    As far as I know "Islands" are groups of polygons that are isolated from the rest of the object's geometry, similarly to the "Fill Bucket" of MS Painter in 2D if we choose a polygon of the mesh and apply the Grow Selection to it infinitely many times it will never reach the "Island" polygons.

                    Selections, well, they are selections we all know what those are but when you asked me if I was bridging Islands or Selections I didn't (and still don't) why it should matter. Doesn't the Bridge behave the same when connecting polygons be it Islands or Selections ? After all Selections are like islands in the sense that we isolate them from the rest of the mesh to apply modifications to them.

                    EDIT:
                    Ah ! the

                    settings.SetBool(c4d.MDATA_BRIDGE_FIRST_SELECT_ONLY, True)
                    settings.SetBool(c4d.MDATA_BRIDGE_SECOND_SELECT_ONLY, True)
                    

                    They were at the bottom of the toolbridge.h with the rest of the UI-related Attributes that I didn't pay attention at all.... there's even a comment line.. how blind am I ?

                    About the Server Error
                    The zip containing my project I was trying to upload was 11,6 KB so I don't know what's wrong with that... tried again and failed. Tried a C4D file also and still failed.
                    The exact message:
                    Something went wrong while parsing server response

                    I am dropping the files in this text field to upload, should I be using a different method ? I don't want to externally link to them (like Dropbox or something else)

                    EDIT #2
                    Ah ! By islands you meant two different objects !

                    EDIT #3
                    I'm having constant crashes when trying to bridge polygon selections from the same object ...
                    Are there specific attributes that need to be left empty when bridging the same object with itself ?
                    For now I'll try to disconnect the target polygon selection and treat it as a different object in order to bridge it...

                    ferdinandF 1 Reply Last reply Reply Quote 0
                    • ferdinandF Offline
                      ferdinand @Dimitris_Derm.
                      last edited by ferdinand

                      Hello @Dimitris_Derm.

                      No, with islands I do not mean different objects. With islands are polygon (selection) islands meant. And that is just the term that is used for these things. The "Plane" object below has two polygon islands, the left and right rectangle shown in the viewport, each composed out of 4 * 5 polygons. They are islands because they are topological disjunct from each other - you cannot 'get' from one island to another without jumping over a gap.

                      a88ac530-c105-430c-bd11-f922f5688881-image.png

                      The same can be applied to selections, as shown below. Now the left polygon island in the mesh has two polygonal selection islands. You cannot get from one selection island to another without jumping over a gap (they are topologically disjunct).

                      bf41be6a-3993-4eb1-b603-438df9aa1bb3-image.png

                      This is a requirement because as my code example demonstrates, when bridging in island mode, you just specify a polygon and a point (and set the flags), and the tool then 'grows out' the to be bridged patch from the given polygon, based on the active polygon selection. And this growing will stop at topological boundaries. So, when you would bridge from the selection in the lower left corner of the left rectangle (to some unspecified target in another mesh), it would only grow into these four polygons. The selection in the top right corner would never be part of the operation.

                      Cheers,
                      Ferdinand

                      MAXON SDK Specialist
                      developers.maxon.net

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