Python PhongSelectionTool [SOLVED]

  • On 08/10/2014 at 06:38, xxxxxxxx wrote:

    Is it possible that PhongSelectionTool to use with Python. I want to set a Phongangle and it is me then output the corresponding edges as selection.

  • On 19/10/2016 at 23:24, xxxxxxxx wrote:

    If anyone has got an example of this, I'd love to see it. I've got a sense of how to call the command, but not how to call the "Select All" button once the tool is active.

  • On 20/10/2016 at 01:58, xxxxxxxx wrote:

    Hi there,

    I´m not quite sure if I understand your questions right...maybe this helps:
    a simple call button example from the docs (actually with a tool).call button
    And the header file of the tool toolphongselection.h


    import c4d  
    from c4d import plugins  
    def main() :  
      if doc.GetAction != 1019730:  
          c4d.CallCommand(1019730, 1019730)  
      tool = plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL)  
      if tool is not None:  
          c4d.CallButton(tool, c4d.PWS_BTN_SELECT_ALL)  
      data = doc.GetActiveToolData()  
    if __name__=='__main__':  

    best wishes

  • On 20/10/2016 at 02:02, xxxxxxxx wrote:


    the plugin ID of a tool and most other elements can be obtained from the "Customize Commands" dialog. With that ID it is possible to enable a tool using SetAction() or CallCommand(). The settings of a tool are stored in a BaseContainer. This BaseContainer can be obtained with GetToolData(). To press a button on a tool one has to get the "plugin" representing that tool. This "plugin" is obtained with FindPlugin(). Then one can press a button with CallButton().

    For handling tools see also the C++ documentation: Active Tool.

    # 1019730 is the tool ID  
    # or  
    # getting the tool settigns  
    toolData = c4d.plugins.GetToolData(doc, 1019730)  
    toolData[c4d.MDATA_PWS_OVERRIDE_PHONG] = True  
    toolData[c4d.MDATA_PWS_ANGLE_THRESHOLD] = 0.25  
    # getting the tool 'plugin'  
    tool = c4d.plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL)  
    if tool is not None:  
      # press buttons  
      c4d.CallButton(tool, c4d.PWS_BTN_SELECT_ALL)  
      c4d.CallButton(tool, c4d.PWS_TAG_ADD_SEL)  

    best wishes,

  • On 20/10/2016 at 14:15, xxxxxxxx wrote:

    Hi Sebastian & monkeytack,

    That's quite helpful, thank you! I'm trying to use CallButton within a Python Generator to create a new spline based on phong-break angles.

    My current strategy is to create a temporary document, clone my object and stuff it into the temp_doc, and then run the PhongSelection tool's "Select All" button. But I'm getting a thread error when I do this.

    The documentation offers this warning for CallButton:
    "Warning Only calls from the main thread!"

    Which I think means I can't call this command from a PythonGenerator. Is that correct?

    If it is, I think I'll need to write my own phong angle edge selection routine.

  • On 21/10/2016 at 00:49, xxxxxxxx wrote:


    this tool (like every other tool) works on the active document (ToolData::Message()) and in this case on the selected (active) polygon objects. So the functionality of a tool can only be applied to the elements of the active document, not to any other (internal) BaseDocument.

    CallButton() emulates user-interaction so it should only be used like user-interaction. And within the generation of of virtual elements like in GetVirtualObjects() or inside the Python Generator obviously no user interaction can happen.

    best wishes,

  • On 21/10/2016 at 13:25, xxxxxxxx wrote:

    Okay, I've written an expression that auto-selects based on phong angle. For the latest version of the code, please see this Github Gist.

    """Select Phong Edges Expression   
    Selects any edges w/ broken phong shading.   
    Last Modified: 2016-10-21   
    Usage Instructions   
    1. Add a Python Expression tag to a polygon object.   
    2. Paste in this code.   
    By Donovan Keith for MAXON USA   
    Feel free to re-use this code in any personal or commercial projects.   
    import c4d   
    import math   
    def YieldEdges(op, nbr) :   
        """Generates a list of a,b points in all edges.   
        vadr = op.GetAllPolygons()   
        for i in xrange(op.GetPolygonCount()) :   
          pli = nbr.GetPolyInfo(i)   
          for side in xrange(4) : # # test all 4 sides of a polygon   
            # Only proceed if edge has not already been processed   
            # and edge really exists (for triangles side 2 from c..d does not exist as c==d)   
            if pli["mark"][side] or side==2 and vadr[i].c==vadr[i].d: continue   
            # One can also skip the side==2 && vadr[i].c==vadr[i].d test as pli["mark"][2] is always True for triangles   
            if side==0:   
              a=vadr[i].a; b=vadr[i].b   
            elif side==1:   
              a=vadr[i].b; b=vadr[i].c   
            elif side==2:   
              a=vadr[i].c; b=vadr[i].d   
            elif side==3:   
              a=vadr[i].d; b=vadr[i].a   
            yield a, b   
    def GetEdgeAngle(poly1, poly2, points) :   
        """Returns the angle between two polygons.   
        Limitation: only takes the first triangle into account.   
        poly1, poly2: CPolygons   
        Return: angle in Radians   
        Source Reference:     
        a1,b1,c1 = points[poly1.a],points[poly1.b],points[poly1.c]   
        n1 = (b1 - a1).Cross(c1 - a1).GetNormalized()   
        a2,b2,c2 = points[poly2.a],points[poly2.b],points[poly2.c]   
        n2 = (b2 - a2).Cross(c2 - a2).GetNormalized()   
        angle_rad = c4d.utils.GetAngle(n1,n2)   
        return angle_rad   
    def GetPhongTag(obj) :   
        """Returns the first PhongTag on object."""   
        if not obj:   
        tags = obj.GetTags()   
        for tag in tags:   
            if tag.GetType() == c4d.Tphong:   
                return tag   
    def GetPhongAngle(obj) :   
        """Returns phong limit angle of obj"""   
        if not obj:   
        phong_tag = GetPhongTag(obj)   
        if not phong_tag:   
            return 0.0   
        angle_limit = phong_tag[c4d.PHONGTAG_PHONG_ANGLELIMIT]   
        if angle_limit:   
            return phong_tag[c4d.PHONGTAG_PHONG_ANGLE]   
            return c4d.utils.Rad(180.0)   
    def PhongSelectEdges(obj, phong_deg=None) :   
        """Selects the edges whose adjoining polys have a > phong_deg angle   
        between them. Also selects broken phong edges. If phong_deg is not   
        specified, the function will calculate based on the Phong tag on the   
        Note: no Undo support or Update calls are made.   
        points = obj.GetAllPoints()   
        polys = obj.GetAllPolygons()   
        # Calculate the phong threshold using the specified angle, or if None the Phong tag on the object   
        phong_angle = None   
        if phong_deg is not None:   
            phong_angle = c4d.utils.Rad(phong_deg)   
            phong_angle = GetPhongAngle(obj)   
            if phong_angle is None:   
                phong_angle = 0   
        # Select Manually Broken Edges   
        neighbor = c4d.utils.Neighbor()   
        edge_count = neighbor.GetEdgeCount()   
        phong_break_edges = obj.GetSelectedEdges(neighbor, c4d.EDGESELECTIONTYPE_PHONG)   
        # Go through every edge   
        for edge_index, edge in enumerate(YieldEdges(obj, neighbor)) :   
            point_a, point_b = edge   
            # Get the neighbor polygons   
            poly1_index, poly2_index = neighbor.GetEdgePolys(point_a, point_b)   
            poly1 = polys[poly1_index]   
            poly2 = polys[poly2_index]   
            # Calculate the difference between them   
            angle = GetEdgeAngle(poly1, poly2, points)   
            # If difference is over a threshold, select the edge   
            if angle >= phong_angle:   
        # Select the Broken Phong Edges + Auto-Broken Edges   
        obj.SetSelectedEdges(neighbor, phong_break_edges, c4d.EDGESELECTIONTYPE_SELECTION)   
    def main() :   
        if not op:   
        # Retrieve the polygon object   
        obj = op.GetObject()   
        if not obj or not obj.IsInstanceOf(c4d.Opolygon) :   

    PS: Sorry for the ugly formatting, for some reason this forum always adds extra spaces to the code I paste.

Log in to reply