I'm trying to create spline outline generator. All is going good, but the resulted spline is invisible for Snapping tool. Even after placing the result directly under the generator (InsertUnder(op)) . It is only working if I'll select the result spline.
Is it something connected to generator cache?
Unsolved Can't snap to Generator output spline
Hello @Madara ,
Welcome to the Plugin Café forum and the Cinema 4D development community, it is great to have you with us!
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:
- Support Procedures: Scope of Support: Lines out the things we will do and what we will not do.
- Support Procedures: Confidential Data: Most questions should be accompanied by code but code cannot always be shared publicly. This section explains how to share code confidentially with Maxon.
- Forum Structure and Features: Lines out how the forum works.
- Structure of a Question: Lines out how to ask a good technical question. It is not mandatory to follow this exactly, but you should follow the idea of keeping things short and mentioning your primary question in a clear manner.
About your First Question
Without your code we cannot do much here, I would recommend having a look at our forum guidelines (as explained above). If I had to take a guess, I would say you are probably overwriting
ObjectData.GetVirtualObjects instead of
.GetContour or you are missing the
OBJECT_ISSPLINE flag when calling
RegisterObjectPlugin, causing either your object not being recognized as a spline or having a malformed cache.
When you implement a spline using
GetVirtualObjects, the cache of that object will be a
SplineObject, or in other words the object itself won't be a spline. When you implement it via
.GetContour, the cache will be a
LineObject (which is the correct cache node type for a spline).
If you got a bit confused by this, you could easily test this in the console by calling
GetCache() on an instance of your plugin. In the example below I compare the cache of a Python generator object which returns a
SplineObject (which would be an example for such faux spline implemented using
.GetVirtualObjects) and a
SplineObject. Although they might look identical in the viewport, they are not the same under the hood.
Hi @ferdinand !
Thank you for your response. It has to be the issue then. Is it possible to convert SplineObject to LineObject somehow?
Here's my code so far:
def main(): parent = c4d.BaseObject(c4d.Onull) distance= op[c4d.ID_USERDATA,10] custom_distance=op[c4d.ID_USERDATA,1] link=op[c4d.ID_USERDATA,5] spline_color=op[c4d.ID_USERDATA,9] outline_only=op[c4d.ID_USERDATA,2] hide_input=op[c4d.ID_USERDATA,3] outline_color=op[c4d.ID_USERDATA,8] final_distance=5 if distance == 0 : final_distance=5 elif distance == 1 : final_distance=8 elif distance==2: final_distance=custom_distance link_clone = link.GetClone() connect_obj = c4d.BaseObject(c4d.Oconnector) link_clone.InsertUnder(connect_obj) if link_clone: #Parametric object pobj = u.SendModelingCommand( command = c4d.MCOMMAND_CURRENTSTATETOOBJECT, list = [connect_obj], mode = c4d.MODELINGCOMMANDMODE_ALL, doc = op.GetMain()) connect_obj = pobj if outline_only: bc = c4d.BaseContainer() settings = c4d.BaseContainer() # Settings settings[c4d.MDATA_SPLINE_OUTLINE] = final_distance # Distance settings[c4d.MDATA_SPLINE_OUTLINESEPARATE] = True #Crée un nouvel objet offspline = u.SendModelingCommand( c4d.MCOMMAND_SPLINE_CREATEOUTLINE, [connect_obj], c4d.MODELINGCOMMANDMODE_ALL, bc=settings, doc=doc) if offspline : offspline.InsertUnder(parent) offspline[c4d.ID_BASEOBJECT_USECOLOR] = 2 # Use Object ColorSpline offspline[c4d.ID_BASELIST_ICON_COLORIZE_MODE]=2 offspline[c4d.ID_BASEOBJECT_COLOR] = outline_color # Red Color # Convert the spline to a line (edges) using a Modeling Command return offspline if not outline_only: #settings[c4d.MDATA_SPLINE_OUTLINESEPARATE] = True #Crée un nouvel objet #connect_obj = c4d.BaseObject(c4d.Oconnector) bc = c4d.BaseContainer() bc.SetData(c4d.MDATA_SPLINE_OUTLINE, final_distance) offspline = u.SendModelingCommand( c4d.MCOMMAND_SPLINE_CREATEOUTLINE, [connect_obj], c4d.MODELINGCOMMANDMODE_ALL, bc) return connect_obj.GetClone()
I'm inputting a null with multiple splines as children, then I put it under Connect object, simplify it, run outline command and get the result.
in short, a Python generator object is not meant to generate splines. You can collapse the cache of your constructed spline and return its
LineObject cache instead of the spline itself. For an example, see . In your case that would be
connect_obj. This will work in the sense that the generator cache will be then like a
SplineObject cache and when you 'Current State to Object' your generator, it will behave like a spline and give you the interpolated editable linear spline and not a spline generator.
However, spline snapping not only inspects caches, but also checks if
OBJECT_ISSPLINE is true. So, you cannot bamboozle it by faking a
SplineObject cache. You will have to implement a proper spline plugin for what you want to do, as you can overwrite there
PS: Your code contains multiple elements that can crash Cinema 4D and/or corrupt the loaded document. Specifically, these sections:
if link_clone: #Parametric object pobj = u.SendModelingCommand( command = c4d.MCOMMAND_CURRENTSTATETOOBJECT, list = [connect_obj], mode = c4d.MODELINGCOMMANDMODE_ALL, doc = op.GetMain()) connect_obj = pobj ... offspline = u.SendModelingCommand( c4d.MCOMMAND_SPLINE_CREATEOUTLINE, [connect_obj], c4d.MODELINGCOMMANDMODE_ALL, bc=settings, doc=doc)
A Python generator's
main() function is subject to the threading restrictions of Cinema 4D because it is just a wrapper for
SendModelingCommand in a threaded context is fine, but you cannot do it on the active document (both
op.GetDocument() are the active document). This is here even worsened by the fact that that the objects in
list are not actually part of the document you pass as
To circumvent that you must create your own document just as I have in  with
temp. Find a more detailed example of that technique in smc_extrude_s26.py.
import c4d op: c4d.BaseObject # The Python generator object. def main() -> c4d.BaseObject: """ """ # A user data Boolean to toggle collapsing the cache of this generator. collapse: bool = op[c4d.ID_USERDATA, 1] spline: c4d.BaseObject = c4d.BaseObject(c4d.Osplinecircle) if not spline: return c4d.BaseObject(c4d.Onull) # Just return the circle spline itself when #collapse is false. if not collapse: return spline # Otherwise grab the LineObject cache of the spline and return a copy of it. temp: c4d.documents.BaseDocument = c4d.documents.BaseDocument() temp.InsertObject(spline) temp.ExecutePasses(c4d.threading.GeGetCurrentThread(), False, False, True, c4d.BUILDFLAGS_NONE) cache: c4d.LineObject | None = spline.GetCache() if not isinstance(cache, c4d.LineObject): return c4d.BaseObject(c4d.Onull) return cache.GetClone(c4d.COPYFLAGS_NONE)