Solved How can I use Plane Cut in Python

Hi!
How can I use the Plane Cut Tool with Python in Cinema4D. I tried the following code but it always fails and returns false as a result. Also: is it possible to specify coordinates by using a vertex (e.g. c4d.Vector(0,0,0) to specify the cut location?

obj = doc.GetActiveObject()
 
settings = c4d.BaseContainer()  # Settings
settings[c4d.MDATA_KNIFEPLANE_MODE] = c4d.MDATA_KNIFEPLANE_MODE_REGION_A
settings[c4d.MDATA_KNIFEPLANE_PLANE_MODE] = c4d.MDATA_KNIFEPLANE_PLANE_MODE_LOCAL
settings[c4d.MDATA_KNIFEPLANE_PLANE] = c4d.MDATA_KNIFEPLANE_PLANE_XZ

result = c4d.utils.SendModelingCommand(
            command=c4d.ID_MODELING_KNIFE_PLANE,  # Use the ID of the modeling command for the cut tool
            list=[obj],
            mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION, 
            bc=settings, 
            doc=doc,
        )

Hello @Christian-0,

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:

About your First Question

You got most things right in your script, but probably missed our resource documentation. There is also the problem that Cinema 4D relies these days on the new modelling core which has not been documented too well for SendModelingCommand yet. Find below my answer as a script.

Cheers,
Ferdinand

Result:
eafa0ea8-6f1e-42da-82c5-eaa795ba1cca-image.png

Code:

"""Demonstrates how to use the plane cut tool with SendModelingCommand (SMC).

Must be run with an editable polygonal geometry selected. For details about SMC see [1]. Tools are
documented in the resources of the docs, the plane cut tool is for example documented here [2]. The
problem is that most SMC (I think all) commands are these days wrapped by the new modelling core
which reimplements most of the modelling operations of Cinema 4D. In case of the plane cut tool
this means for example that MDATA_KNIFEPLANE_PIVOT_POSITION and MDATA_KNIFEPLANE_PIVOT_ROTATION are 
not in use anymore, being replaced by MDATA_KNIFEPLANE_MATRIX.

This means a few things:

* You cannot mimic each aspect of a tool with SMC. That has always been the case. You alternatively
 can manipulate the tool container of the tool and invoke `CallCommand` as shown here [3] but there
 you will probably run into problems with the mouse inputs.
* The new modelling core re-imagines things and ignores a good portion of the settings you can see
 in the UI and adds a new field, MDATA_KNIFEPLANE_MATRIX. These are the fields that are evaluated
 by the new modelling core:

    mcd.bc->GetMatrix(MDATA_KNIFEPLANE_MATRIX)
    mcd.bc->GetInt32(MDATA_KNIFEPLANE_CONUT)
    mcd.bc->GetFloat(MDATA_KNIFEPLANE_OFFSET)
    mcd.bc->GetFloat(MDATA_KNIFEPLANE_DIST)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_SELECTED)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_SELECT_CUT)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_CUTPOLYS)
    mcd.bc->GetInt32(MDATA_KNIFEPLANE_MODE)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_NGON_CURVATURE)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_REGULARSLICE)

References:
    [1]: https://github.com/PluginCafe/cinema4d_py_sdk_extended/tree/master/scripts/04_3d_concepts/modeling/modeling_commands
    [2]: https://developers.maxon.net/docs/py/2023_2/classic_resource/tool/toolknifeplane.html
    [3]: https://plugincafe.maxon.net/topic/12298/toggle-knife-cut-planes/
"""

import c4d

op: c4d.BaseObject # The active object.
doc: c4d.documents.BaseDocument # The currently active document.

def main() -> None:
    """Runs the example.
    """
    # Sort out a non polygon object being selected.
    if not isinstance(op, c4d.PolygonObject):
        raise TypeError(f"{op = }")
    
    # The settings container for the plane cut we will carry out.
    bc: c4d.BaseContainer = c4d.BaseContainer(c4d.ID_MODELING_KNIFE_PLANE)

    # The modelling core uses a matrix to define the cut instead of the two vectors of the classic
    # API tool. We define here a cutting plane +100 units on the y axis which is rotated by 45° ccw
    # on the x-axis.
    bc[c4d.MDATA_KNIFEPLANE_MATRIX] = (c4d.utils.MatrixRotX(c4d.utils.DegToRad(45.)) * 
                                       c4d.utils.MatrixMove(c4d.Vector(0, 100, 0)))
    bc[c4d.MDATA_KNIFEPLANE_CONUT] = 4       # We want to make four cuts.
    bc[c4d.MDATA_KNIFEPLANE_DIST] = 25.      # Which are 25 units apart each.
    bc[c4d.MDATA_KNIFEPLANE_CUTPOLYS] = True # This has to be true, the tool will fail otherwise.
                                             # Don't ask me why :)

    # Add an undo item for the plane cut we are going to carry out.                                      
    doc.StartUndo()
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)

    # Carry out the command.
    if not c4d.utils.SendModelingCommand(c4d.ID_MODELING_KNIFE_PLANE, [op],
        c4d.MODELINGCOMMANDMODE_ALL, bc, doc):
        print (f"Failed to run plane cut tool in the modelling core on {op}.")

    # CLose the undo and push an update event to the core of Cinema 4D.
    doc.EndUndo()
    c4d.EventAdd()

if __name__ == "__main__":
    main()

MAXON SDK Specialist
developers.maxon.net

Hello @Christian-0,

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:

About your First Question

You got most things right in your script, but probably missed our resource documentation. There is also the problem that Cinema 4D relies these days on the new modelling core which has not been documented too well for SendModelingCommand yet. Find below my answer as a script.

Cheers,
Ferdinand

Result:
eafa0ea8-6f1e-42da-82c5-eaa795ba1cca-image.png

Code:

"""Demonstrates how to use the plane cut tool with SendModelingCommand (SMC).

Must be run with an editable polygonal geometry selected. For details about SMC see [1]. Tools are
documented in the resources of the docs, the plane cut tool is for example documented here [2]. The
problem is that most SMC (I think all) commands are these days wrapped by the new modelling core
which reimplements most of the modelling operations of Cinema 4D. In case of the plane cut tool
this means for example that MDATA_KNIFEPLANE_PIVOT_POSITION and MDATA_KNIFEPLANE_PIVOT_ROTATION are 
not in use anymore, being replaced by MDATA_KNIFEPLANE_MATRIX.

This means a few things:

* You cannot mimic each aspect of a tool with SMC. That has always been the case. You alternatively
 can manipulate the tool container of the tool and invoke `CallCommand` as shown here [3] but there
 you will probably run into problems with the mouse inputs.
* The new modelling core re-imagines things and ignores a good portion of the settings you can see
 in the UI and adds a new field, MDATA_KNIFEPLANE_MATRIX. These are the fields that are evaluated
 by the new modelling core:

    mcd.bc->GetMatrix(MDATA_KNIFEPLANE_MATRIX)
    mcd.bc->GetInt32(MDATA_KNIFEPLANE_CONUT)
    mcd.bc->GetFloat(MDATA_KNIFEPLANE_OFFSET)
    mcd.bc->GetFloat(MDATA_KNIFEPLANE_DIST)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_SELECTED)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_SELECT_CUT)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_CUTPOLYS)
    mcd.bc->GetInt32(MDATA_KNIFEPLANE_MODE)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_NGON_CURVATURE)
    mcd.bc->GetBool(MDATA_KNIFEPLANE_REGULARSLICE)

References:
    [1]: https://github.com/PluginCafe/cinema4d_py_sdk_extended/tree/master/scripts/04_3d_concepts/modeling/modeling_commands
    [2]: https://developers.maxon.net/docs/py/2023_2/classic_resource/tool/toolknifeplane.html
    [3]: https://plugincafe.maxon.net/topic/12298/toggle-knife-cut-planes/
"""

import c4d

op: c4d.BaseObject # The active object.
doc: c4d.documents.BaseDocument # The currently active document.

def main() -> None:
    """Runs the example.
    """
    # Sort out a non polygon object being selected.
    if not isinstance(op, c4d.PolygonObject):
        raise TypeError(f"{op = }")
    
    # The settings container for the plane cut we will carry out.
    bc: c4d.BaseContainer = c4d.BaseContainer(c4d.ID_MODELING_KNIFE_PLANE)

    # The modelling core uses a matrix to define the cut instead of the two vectors of the classic
    # API tool. We define here a cutting plane +100 units on the y axis which is rotated by 45° ccw
    # on the x-axis.
    bc[c4d.MDATA_KNIFEPLANE_MATRIX] = (c4d.utils.MatrixRotX(c4d.utils.DegToRad(45.)) * 
                                       c4d.utils.MatrixMove(c4d.Vector(0, 100, 0)))
    bc[c4d.MDATA_KNIFEPLANE_CONUT] = 4       # We want to make four cuts.
    bc[c4d.MDATA_KNIFEPLANE_DIST] = 25.      # Which are 25 units apart each.
    bc[c4d.MDATA_KNIFEPLANE_CUTPOLYS] = True # This has to be true, the tool will fail otherwise.
                                             # Don't ask me why :)

    # Add an undo item for the plane cut we are going to carry out.                                      
    doc.StartUndo()
    doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)

    # Carry out the command.
    if not c4d.utils.SendModelingCommand(c4d.ID_MODELING_KNIFE_PLANE, [op],
        c4d.MODELINGCOMMANDMODE_ALL, bc, doc):
        print (f"Failed to run plane cut tool in the modelling core on {op}.")

    # CLose the undo and push an update event to the core of Cinema 4D.
    doc.EndUndo()
    c4d.EventAdd()

if __name__ == "__main__":
    main()

MAXON SDK Specialist
developers.maxon.net

Thank you very much! Now it is working.