0

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)
Ku Mu
  • 21
  • 6
  • What values do you get when you do a `print( _rotation )` -vs- what values does `coordsRoot.rotation.Q` expect? – Doyousketch2 Jun 27 '21 at 20:10
  • Vector=[App.Vector(0.0, 0.0,0.0)] ; --> rotation.Q =(1.0,1.0,1.0, pi/2) The angle is 90, the axis of rotation lets be what ever x, or y, or z. I wrote x,y,z to be 1. and lets the arrow start drawing at the origin . Remember that the angle must be in radians – Ku Mu Jun 27 '21 at 20:14
  • The value is not wrong but the drawing will not rotate – Ku Mu Jun 27 '21 at 20:34
  • Hmm, do you have to add head & tail **before** applying scale/translation/rotation? `so_separatorRoot .addChild(so_separatorHead) .addChild(so_separatorTail) .addChild(coordsRoot)` – Doyousketch2 Jun 27 '21 at 20:40
  • No difference. I tried to change the location of them with no results – Ku Mu Jun 27 '21 at 21:03

1 Answers1

0

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)
Ku Mu
  • 21
  • 6