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:
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
from c4d import plugins
def main() :
if doc.GetAction != 1019730:
tool = plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL)
if tool is not None:
data = doc.GetActiveToolData()
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
# 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
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.
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
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.
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"] is always True for triangles
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
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)
def GetPhongTag(obj) :
"""Returns the first PhongTag on object."""
if not obj:
tags = obj.GetTags()
for tag in tags:
if tag.GetType() == c4d.Tphong:
def GetPhongAngle(obj) :
"""Returns phong limit angle of obj"""
if not obj:
phong_tag = GetPhongTag(obj)
if not phong_tag:
angle_limit = phong_tag[c4d.PHONGTAG_PHONG_ANGLELIMIT]
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.