Error after hitting Undo.



  • Hello,

    the actual script or a part of it would help yes.

    I've also marked this thread as a question as you seem to never do it ;p

    Cheers,
    Manuel.



  • I made the changes in order to work on a duplicate of the original spline.
    It still works, but it also still returns the same error when I undo.
    Here is the script:

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    
    # Find the length of the spline segment between points p1 and p2
    def GetLength(op,p1,p2):
        select=op.GetPointS()
        select.DeselectAll()
        select.Select(p1)
        select.Select(p2)
    
        bc=c4d.BaseContainer()
        result=c4d.utils.SendModelingCommand(c4d.MCOMMAND_SPLIT, [op], mode=c4d.MODELINGCOMMANDMODE_POINTSELECTION, bc=bc, doc=doc)
        leng=10000000.0
        if result!=False and result!=[]:
            op2=result[0]
            segm=c4d.utils.SplineHelp()
            segm.InitSplineWith(op2, flags=c4d.SPLINEHELPFLAGS_GLOBALSPACE|c4d.SPLINEHELPFLAGS_CONTINUECURVE)
            leng=segm.GetSplineLength()
            segm.FreeSpline()
        return leng
    
    # Main function
    def main():
        selected=doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_0)
        if len(selected) == 0:
            c4d.gui.MessageDialog("You must select a spline and two consecutive points of that spline.")    
            return
    
        op=selected[0]
        if op.GetType()!=5101:
            c4d.gui.MessageDialog("You must select a spline and two consecutive points of that spline.")    
            return
    
        selection=op.GetPointS()
        if selection.GetCount()!=2:
            c4d.gui.MessageDialog("You must select two consecutive points of the spline.")
            return
    
        # check if the selected points are consecutive
        p1,p2=-1,-1
        num=op.GetPointCount()
        for s in range(num):
            if selection.IsSelected(s):
                if p1==-1:
                    p1=s
                else:
                    p2=s
    
        if p2-p1!=1:
            c4d.gui.MessageDialog("You must select two consecutive points of the spline.")
            return
    
        # get the size of the segment
        shortest=GetLength(op,p1,p2)
        
        # work on a copy of the original spline
        op2=op.GetClone()
    
        # start at point 0
        i=0
        while i<num:
            # get the length of the current segment between point i and i+1
            new_length=GetLength(op2,i,i+1)
    
            # if the segment is, at least one and a half times the size of the initial segment...
            if (new_length>(shortest*1.5)):
                subdivs=int(new_length/shortest)+1
    
                # select point i and i+1
                selection=op2.GetPointS()
                selection.DeselectAll()
                selection.Select(i)
                selection.Select(i+1)
    
                # subdivide that segment
                bc=c4d.BaseContainer()
                bc.SetInt32(c4d.MDATA_SUBDIVIDE_SPLINESUB,subdivs)
                result=c4d.utils.SendModelingCommand(c4d.MCOMMAND_SUBDIVIDE, [op2], mode=c4d.MODELINGCOMMANDMODE_POINTSELECTION, bc=bc, doc=doc)
                
                # update the counter
                i=i+subdivs-1
                # update the limit
                num=num+subdivs-1
            
            # increase the counter
            i=i+1
    
        # insert the new subdivided spline after the original spline
        # and delete the original spline, making sure this is undoable
        doc.StartUndo()
        doc.InsertObject(op2, parent=None, pred=op, checknames=False)
        doc.AddUndo(c4d.UNDOTYPE_NEW, op2)
        doc.AddUndo(c4d.UNDOTYPE_DELETE, op)    
        op.Remove()
        doc.EndUndo()
        
        # update the document
        c4d.EventAdd()
    
    # Execute main()
    if __name__=='__main__':
        main()
    


  • @m_magalhaes said in Error after hitting Undo.:

    I've also marked this thread as a question as you seem to never do it ;p

    How can I mark it as a question?



  • I finally made it work without the error after hitting undo, by replacing calls to GetLength, in the form:

    GetLength(op,p1,p2)

    to

    GetLength(op.GetClone(),p1,p2)



  • Hello,

    i just scratch a bit your code, but i've discovered that with the R21, MCOMMAND_SPLIT only return true.
    I've opened a bug entry for that.

    Happy to see your code is working. I will have a look at it and my comment on that.
    Like it's not a good idea to use GetType() you should use IsInstanceOf

    About the forum, those are the thread where you can have information on how to use the new functionalities of the forum. This will help futur user to find resolved question and the right post.



  • Thank you, Manuel.

    From what I see, several things are working differently in R21.
    I suspect the MCOMMAND_EDGE_TO_SPLINE is also not working properly.
    And the MCOMMAND_CURRENTSTATETOOBJECT (a very important one) is also not working as expected, requiring that the object to be converted to be in a new document.

    I will start using IsInstanceOf instead of GetType :-)

    I will also pay more attention to the tagging part of my posts.

    Once again, thank you.



  • @rui_mac said in Error after hitting Undo.:

    MCOMMAND_CURRENTSTATETOOBJECT

    This one is fixed on the next update.

    I'll check MCOMMAND_EDGE_TO_SPLINE thanks.



  • hello,

    just dig in a little bit more on your code.
    I've added some AddUndo and i'm using the flag of the SendModelingCommand to add an undo.
    Removing the need of a clone except in the GetLength function where you have to split the spline.

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    
    # Find the length of the spline segment between points p1 and p2
    def GetLength(op,p1,p2):
        newSpline  = op.GetClone()
    
        select = newSpline.GetPointS()
        select.DeselectAll()
        select.Select(p1)
        select.Select(p2)
    
        bc = c4d.BaseContainer()
        result=c4d.utils.SendModelingCommand(c4d.MCOMMAND_SPLIT, [newSpline], mode=c4d.MODELINGCOMMANDMODE_POINTSELECTION, bc=bc, doc=doc)
        leng = 10000000.0
        if result:
            print "ok "
            segm=c4d.utils.SplineHelp()
            segm.InitSplineWith(result[0], flags=c4d.SPLINEHELPFLAGS_GLOBALSPACE|c4d.SPLINEHELPFLAGS_CONTINUECURVE)
            leng=segm.GetSplineLength()
            segm.FreeSpline()
            print leng
        return leng
    
    # Main function
    def main():
        selected = doc.GetActiveObject() if  doc.GetActiveObject().IsInstanceOf(c4d.Ospline) else None
        if selected is None:
            c4d.gui.MessageDialog("Select a spline")    
            return
    
        selection = op.GetPointS()
        if selection.GetCount() != 2:
            c4d.gui.MessageDialog("You must select two points of the spline.")
            return
    
        # check if the selected points are consecutive
        p1 = p2 = -1
    
        num = op.GetPointCount()
        for s in range(num):
            if selection.IsSelected(s):
                if p1 == -1:
                    p1 = s
                else:
                    p2 = s
    
        if p2-p1 != 1:
            c4d.gui.MessageDialog("You must select two consecutive points of the spline.")
            return
    
        # get the size of the segment
        shortest = GetLength(op,p1,p2)
        
        # start at point 0
        i = 0
        doc.StartUndo()
        while i<num:
            # get the length of the current segment between point i and i+1
            new_length = GetLength(op,i,i+1)
    
            # if the segment is, at least one and a half times the size of the initial segment...
            if (new_length > (shortest * 1.5)):
                subdivs=int(new_length/shortest)+1
    
                # select point i and i+1
                selection=op.GetPointS()
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                selection.DeselectAll()
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                selection.Select(i)
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                selection.Select(i+1)
    
                # subdivide that segment
                bc=c4d.BaseContainer()
                bc.SetInt32(c4d.MDATA_SUBDIVIDE_SPLINESUB,subdivs)
    
                result=c4d.utils.SendModelingCommand(c4d.MCOMMAND_SUBDIVIDE, [op], mode=c4d.MODELINGCOMMANDMODE_POINTSELECTION, bc=bc, doc=doc, flags =c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)
                if result == False:
                    raise ValueError("the subdivde command failed")
                # update the counter
                i=i+subdivs-1
                # update the limit
                num=num+subdivs-1
            
            # increase the counter
            i=i+1
    
        doc.EndUndo()
        
        
        # update the document
        c4d.EventAdd()
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    Cheers,
    Manuel



  • @rui_mac said in Error after hitting Undo.:

    I suspect the MCOMMAND_EDGE_TO_SPLINE is also not working properly.

    what doesn't work properly ?

    import c4d
    from c4d import gui
    from c4d import utils
    
    def main():
        #edge to spline.    
        bc = c4d.BaseContainer()
        res = utils.SendModelingCommand(c4d.MCOMMAND_EDGE_TO_SPLINE, list = [op], bc = bc, doc= doc)
        c4d.EventAdd()
    
    # Execute main()
    if __name__=='__main__':
        main()
    


  • The addition of the undo as a flag is great. Thank you :-)

    What was not working was that, in R21, I was getting no spline as the return result of the SendModelingCommand, set to MCOMMAND_EDGE_TO_SPLINE.
    I will try again, at home, as I don't have R21 here, at work.


Log in to reply