Search code examples
pythonfreecad

pivy.coin (COIN3D) Arrow-drawing is not rotating (FreeCAD - Python)


In my mind the code below is correct. But unfortunately I cannot rotate the arrow. Whatever angle I give to the function, it doesn't work. I don't know what is wrong with this code.

Note: This is a part of my COIN3D Widget system I build for FreeCAD. you find the whole project at my github = https://github.com/MariwanJ/Design456/tree/devbranch

#draw an arrow 
def draw_arrow(_Points=[], _color=(0,1,0), _ArrSize=1.0,_rotation=(1.0,1.0,1.0,0.0) ):
    print("point,arrsize,rota",_Points,_ArrSize,_rotation)
    if len (_Points)!=2:
        raise ValueError('must be 2 points')
    try:
        so_separatorRoot=coin.SoSeparator()
        so_separatorHead = coin.SoSeparator()
        so_separatorTail = coin.SoSeparator()
        
        transHead = coin.SoTranslation()   # decide at which position the object will be placed
        transTail = coin.SoTranslation()   # decide at which position the object will be placed
        transRoot= coin.SoTranslation()    # decide at which position the whole objects will be placed
        
        coordsRoot = coin.SoTransform()
        
        cone=coin.SoCone()
        cone.bottomRadius= 3
        cone.height= 3
        
        cylinder=coin.SoCylinder()
        cylinder.height = 10
        cylinder.radius = 0.5
        p1=_Points[0]
        p2=App.Vector(p1.x,p1.y-5,p1.z)

        styleHead = coin.SoDrawStyle()
        styleTail = coin.SoDrawStyle()
        
        styleHead.style = coin.SoDrawStyle.LINES     #draw only frame not filled
        styleHead.lineWidth = 3

        styleTail.style = coin.SoDrawStyle.LINES     #draw only frame not filled
        styleTail.lineWidth = 2
        
        coordsRoot.scaleFactor.setValue([_ArrSize,_ArrSize,_ArrSize])
        coordsRoot.translation.setValue(App.Vector(0,0,0))
        coordsRoot.rotation.Q=_rotation #  SbRotation (const SbVec3f &axis, const float radians)

        transHead.translation.setValue(p1)
        transTail.translation.setValue(p2)
        transRoot.translation.setValue(App.Vector(0.0,0.0,0.0))
        
        color=coin.SoBaseColor(); 
        color.rgb=_color
        
        so_separatorHead.addChild(color)
        so_separatorTail.addChild(color)
        
        so_separatorHead.addChild(transHead)
        so_separatorTail.addChild(transTail)

        so_separatorHead.addChild(styleHead)
        so_separatorHead.addChild(cone)
        
        so_separatorTail.addChild(styleTail)
        so_separatorTail.addChild(cylinder)
        
        so_separatorRoot.addChild(transRoot)
        so_separatorRoot.addChild(color)
        so_separatorRoot.addChild(coordsRoot)
        so_separatorRoot.addChild(so_separatorHead)
        so_separatorRoot.addChild(so_separatorTail)
        
        return so_separatorRoot

    except Exception as err:
        App.Console.PrintError("'Design456_DirectScale' Failed. "
                               "{err}\n".format(err=str(err)))
        exc_type, exc_obj, exc_tb = sys.exc_info()
        fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
        print(exc_type, fname, exc_tb.tb_lineno)

Solution

  • I found the solution. Actually I had the answer in the question. Look at the line: coordsRoot.rotation.Q=_rotation # SbRotation (const SbVec3f &axis, const float radians)

    It is mentioned there that you must give four float values .. My bad. But the problem with Python is .. It doesn't generate any error. That made my troubleshooting too difficult. There is no (.Q) as a sub-object for that (SbRotation). I write down the correct code just in case anyone else want to use it.

    def draw_arrow(_Points=[], _color=FR_COLOR.FR_OLIVE, _ArrSize=1.0,_rotation=(1.0,1.0,1.0,0.0)):
        '''
        Draw a 3D arrow at the position given by the _Points and the color given by _color. 
        Scale it by the _ArrSize, and rotate it by the _rotation which consist of four float values(x,y,z ,and Angel), angle in radians. 
        '''
        if len (_Points)!=2:
            raise ValueError('Vertices must be 2')
        try:
            so_separatorRoot=coin.SoSeparator()
            so_separatorHead = coin.SoSeparator()
            so_separatorTail = coin.SoSeparator()
            
            transHead = coin.SoTranslation()   # decide at which position the object will be placed
            transTail = coin.SoTranslation()   # decide at which position the object will be placed
            transRoot= coin.SoTranslation()    # decide at which position the whole objects will be placed
            
            coordsRoot = coin.SoTransform()
            
            cone=coin.SoCone()
            cone.bottomRadius= 3
            cone.height= 3
            
            cylinder=coin.SoCylinder()
            cylinder.height = 10
            cylinder.radius = 0.5
            p1=_Points[0]
            p2=App.Vector(p1.x,p1.y-5,p1.z)
    
            styleHead = coin.SoDrawStyle()
            styleTail = coin.SoDrawStyle()
            
            styleHead.style = coin.SoDrawStyle.LINES     #draw only frame not filled
            styleHead.lineWidth = 3
    
            styleTail.style = coin.SoDrawStyle.LINES     #draw only frame not filled
            styleTail.lineWidth = 2
            
            coordsRoot.scaleFactor.setValue([_ArrSize,_ArrSize,_ArrSize])
            coordsRoot.translation.setValue(App.Vector(0,0,0))
            coordsRoot.rotation.setValue(_rotation) #  SbRotation (const SbVec3f &axis, const float radians)
            
    
            transHead.translation.setValue(p1)
            transTail.translation.setValue(p2)
            transRoot.translation.setValue(App.Vector(0.0,0.0,0.0))
            
            color=coin.SoBaseColor(); 
            color.rgb=_color
            
            so_separatorHead.addChild(color)
            so_separatorTail.addChild(color)
            
            so_separatorHead.addChild(transHead)
            so_separatorTail.addChild(transTail)
    
            so_separatorHead.addChild(styleHead)
            so_separatorHead.addChild(cone)
            
            so_separatorTail.addChild(styleTail)
            so_separatorTail.addChild(cylinder)
    
            print("rotatin",_rotation)
            so_separatorRoot.addChild(coordsRoot)       
            so_separatorRoot.addChild(transRoot)
            so_separatorRoot.addChild(so_separatorHead)
            so_separatorRoot.addChild(so_separatorTail)
    
            
            return so_separatorRoot
            # we have a selected object. Try to show the dimensions. 
            
        except Exception as err:
            App.Console.PrintError("'Design456_DirectScale' Failed. "
                                   "{err}\n".format(err=str(err)))
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)