Jump to content

SharpEars

Registered Member
  • Posts

    196
  • Joined

  • Last visited

  • Days Won

    5

Everything posted by SharpEars

  1. More Useful Measure Object 2.0, initial proof of concept (note the additional gradations that can also be used as Axis Snap points at 25%, 50%, and 75% of the lengths of the measure arrow vectors): From this: to this:
  2. You're not nitpicking - these are all perfectly valid points and I have corrected the source in the above post, accordingly. Michael P.S. The next feature I am planning to add is to record the distance of each arrow in the name of the Null, for further clarity and information/disambiguation, especially when multiple runs of this script are used to store historic states of a Measure Object. Stay tuned and let me know if you can think of any other useful tidbits that should be added...
  3. Ever wanted to snap to the arrowheads of a Measure Object? Well, now you can using this script I wrote, which creates Null objects as children of a Measure Object and positions them at its arrowheads' tips (that can then be snapped to using Axis Snap). Use the Script Manager to copy this script in, name it, save it, and perhaps create a toolbar button for it if it's something you will use often. If you come up with reasonable suggestions for enhancement of this script or find any bugs, please feel free to provide the details in a reply to this post and I will consider implementing/fixing them. Important note: The Measure Object has to be part of the Object Hierarchy and selected. You can add it to the Object Hierarchy by clicking on the Create Object button after creating the measurement points using the Measure & Construction tool. Also, you can run the script multiple times for the same Measure Object, after changing its points coordinates, in order to get new Null object children to be created at the modified point locations (the positions of existing Null children of the Measure Object will not auto-refresh if the Measure Object's points get modified. This allows for the recording of historic positions of the Measure object's arrowhead points by running the script each time a change is made to the Measure Object's measurement arrows): nulls_on_measure_object_arrowheads.py import c4d import c4d.gui # Functionality Provided: # Creates nulls at active Measure Object's arrowhead points. Can be used to allow "Axis Snap" at those points. # The colors of the nulls will correspond with the (current) colors of the arrows, for clarity. # The script is written in a "professional" manner (i.e., not as the sort of hack you oft see posted) and contains # proper comments describing what various code does. # Also, supports proper Undo functionality, like the existing Core C4D tools # Create a null object at one of the measure object's arrowheads def create_null_at_measure_point(measure_obj,null_name,null_pos,color): # Create the null null_obj=c4d.BaseObject(c4d.Onull) # Set various attributes of the null null_obj.SetName(null_name) null_obj.SetAbsPos(null_pos) null_obj[c4d.NULLOBJECT_DISPLAY]=c4d.NULLOBJECT_DISPLAY_POINT # Use "locator" null object shape null_obj[c4d.ID_BASEOBJECT_USECOLOR]=1 # Automatic null_obj[c4d.ID_BASEOBJECT_COLOR]=color # Get from measure # Let's add the new null object as the last child of the Measure Object # Get the last child of the Measure (if any children are present), otherwise will be set to None last_child_obj_of_measure=measure_obj.GetDownLast() # Add the null object to the Object Hierarchy as the last child of the Measure Object # Note: Setting checknames to True will cause C4D to add a .1, .2, etc., suffix if there is a name collision doc.InsertObject(null_obj,measure_obj,pred=last_child_obj_of_measure,checknames=True) # Needs to be called after creation (and insertion into the document, thanks to C4D Cafe user # MighT for pointing out the UNDO step sequencing with regard to document insertion) doc.AddUndo(c4d.UNDOTYPE_NEW, null_obj) # Entry point into script def main(): # Make sure that there is an active object and that it is a Measure Object if op is not None and op.GetType()==c4d.ID_MEASURE_OBJECT: point1_pos=op[c4d.MDATA_MEASURE_PNT1_VECTOR] # Unused, for now # Start Undoable action doc.StartUndo() # If point 2 is in "World Mode" # BTW: World mode is MDATA_MEASURE_PNT_MODE_FREE (who would have thunk it?!) if op[c4d.MDATA_MEASURE_PNT1_MODE]==c4d.MDATA_MEASURE_PNT_MODE_FREE: # Create a locator null at its arrowhead's tip create_null_at_measure_point( op, null_name="Second point tip", null_pos=op[c4d.MDATA_MEASURE_PNT2_VECTOR], color=op[c4d.MDATA_MEASURE_COLOR1]) # Use color of second point, that's how C4D has them numbered (COLOR1 is for point 2) # Is a third point present (and in "World Mode?") if op[c4d.MDATA_MEASURE_3RD_POINT] and op[c4d.MDATA_MEASURE_PNT2_MODE]==c4d.MDATA_MEASURE_PNT_MODE_FREE: # Throw a locator null on that puppy, too create_null_at_measure_point( op, null_name="Third point tip", null_pos=op[c4d.MDATA_MEASURE_PNT3_VECTOR], color=op[c4d.MDATA_MEASURE_COLOR2]) # Use color of third point, yes COLOR2 is the color of the third point # Done (with proper undo handling) doc.EndUndo() # Trigger UI refresh/repaint c4d.EventAdd() else: c4d.gui.MessageDialog('Please make sure that a Measure Object is the current active selection, before running this script.') # Execute main() if __name__=='__main__': main()
  4. Nothing actionable, I am afraid, and a misunderstanding of the question posed. I was hoping someone here would know the answer.
  5. c4d.PolygonObject has a method called SetSelectedEdges() which is documented as follow (quoted from most current help, i.e. from C4D S22) PolygonObject.SetSelectedEdges(self, e, pSel, ltype) Set the selected, hidden or phong break edges. The edges are indexed uniquely by a Neighbor object, so each edge has a single index. Note This is a convenience wrapper around GetEdgeS(), GetEdgeH() and GetPhongBreak(). Parameters: e (c4d.utils.Neighbor) – The neighbor object with information about the edge topology. Must be initialized with all polygons, i.e. with Neighbor.Init(). pSel (c4d.BaseSelect) – The edge to select. ltype (int) – The type of selection to get: EDGESELECTIONTYPE_SELECTION Selected edges. EDGESELECTIONTYPE_HIDDEN Hidden edges. EDGESELECTIONTYPE_PHONG Phong edges. Return type: bool Returns: True if the selection succeeded, otherwise False. OK, that's great, I populate the c4d.BaseSelect with all of the edge indices (using the Neighbor object's definition of logical edge indices) that I want to select and the c4d.utils.Neighbor object takes care of figuring out which physical edges and polygons they belong to, in order to make sure that the selection is "valid." What is the definition of validity here? Well apparently, we need to make sure to select all physical edges across all polygons that share said physical edges. In other words, instead of selecting a physical edge once, we would have to select it potentially multiple times, once for each of the polygons sharing said edge. The help for GetEdgeS(), tells us this information in the red Warning text: PolygonObject.GetEdgeS(self) Get the selected edges. The edges are indexed by 4 * polygon + edge where polygon is the polygon index and edge is the edge index between 0 and 3. Warning If you change this selection you must make sure that its still valid, so that shared edges have a well-defined selection status. It is safer to use SetSelectedEdges(). Return type: c4d.BaseSelect Returns: A reference to the selection of visible edges. The Warning text tells us to use SetSelectedEdges() with a Neighbor object to make sure that any edges we select which are shared by multiple polygons (i.e., non-boundary edges) get selected with respect to all polygons that share said edges (the definition of "valid," as previously described). OK, that certainly sounds convenient. Instead of trying to fish for all of the physical edges across all polygons when I would like to select an edge. I can just choose a single edge by index in the Neighbor object and let it figure out what physical edges my logical edge represents. The Problem How in the world can I choose the edges to select by index from the Neighbor object (for use in my BaseSelect), if the c4d.utils.Neighbor class offers no way to get the properties of logical edges by their index (as stored somewhere internally in the Neighbor object). The only thing I see available is a GetEdgeCount() method which returns the number of (logically distinct) edges and in effect defines the set of logical Edge indices as a range from 0 to GetEdgeCount()-1. What I don't see is a method to get the properties of an edge by logical edge index. It seems to me that the notion of a logical edge index is completely opaque to users of the Neighbor class and if this is the case, how can one refer to edges by their logical index in the Neighbor object, not knowing what edges they are referencing? As a case in point, below is the entire API for the c4d.utils.Neighbor class (aside from polygon assignment via Init() and discard via Flush(), which are not relevant to the discussion). There is not a single method here that tells me which actual edge (or properties of an edge) a logical edge index refers to, so I that I can select edges by index in a BaseSelect object and use the BaseSelect to define a selection range for the pSel argument of the PolygonObject.SetSelectEdges() method. # Note that, for all of the methods below that use these, a, b, and pnt are point indices # in the polygon and poly is the polygon index. The notion of an edge index is nowhere # to be seen! Neighbor.GetNeighbor(self, a, b, poly) Neighbor.GetPointPolys(self, pnt) Neighbor.GetEdgePolys(self, a, b) # Get the total number of edges found. Neighbor.GetEdgeCount(self) # Get a dict that contains neighbor information about the given polygon. # One can use this to browse through all available edges using the following code # (My edit: Gives you the kitchen sink. Does not give you any info about edge indices # in the Neighbor object, though, and how they relate to specific edges.) Neighbor.GetPolyInfo(self, poly) # Gets the points that are attached through one edge to the given point. Neighbor.GetPointOneRingPoints(self, pnt) Am I overlooking something?
  6. The reason Python is slower than XPresso is because many of the XPresso nodes were created using compiled C++ code. You can speed up your Python code by precomputing everything possible and just looking up, or better yet, iterating over the precomputed values. Just to give you an example, take your lfo function: def lfo(cframe, frecuencia, amplitud=1): return 1-(((math.sin(cframe*frecuencia)*amplitud)+1)*0.5) After computing a result that is a function of a permutation of the input values, you can cache it by storing it into a dict(), keyed by a tuple consisting of the inputs. Assuming the number of permutations of your inputs is relatively small and discrete, this can speed things up. In similar fashion, use Dynamic Programming whenever possible. If you are not familiar with this concept, you can read about it on the Geeks for Geeks web site. Basically, cache everything you can after it is calculated once and use the cached values from that point on.
×
×
  • Create New...