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.
greetz
iDani -
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.hor:
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) c4d.EventAdd() data = doc.GetActiveToolData() data.SetBool(c4d.MDATA_PWS_ADD_TO_SEL,True) if __name__=='__main__': main()
best wishes
Martin -
On 20/10/2016 at 02:02, xxxxxxxx wrote:
Hello,
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 doc.SetAction(1019730) # or #c4d.CallCommand(1019730) # 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) c4d.EventAdd()
best wishes,
Sebastian -
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:
Hello,
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,
Sebastian -
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 v0.0.1 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: https://developers.maxon.net/forum/topic/9587/12869_getting-the-full-angle-between-faces """ 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: return 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: return 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] else: 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 object. 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) else: phong_angle = GetPhongAngle(obj) if phong_angle is None: phong_angle = 0 # Select Manually Broken Edges neighbor = c4d.utils.Neighbor() neighbor.Init(obj) 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: phong_break_edges.Select(edge_index) # Select the Broken Phong Edges + Auto-Broken Edges obj.SetSelectedEdges(neighbor, phong_break_edges, c4d.EDGESELECTIONTYPE_SELECTION) def main() : if not op: return # Retrieve the polygon object obj = op.GetObject() if not obj or not obj.IsInstanceOf(c4d.Opolygon) : return PhongSelectEdges(obj)
PS: Sorry for the ugly formatting, for some reason this forum always adds extra spaces to the code I paste.