Giter Site home page Giter Site logo

port SoQt to PySide about pivy HOT 21 CLOSED

coin3d avatar coin3d commented on May 24, 2024
port SoQt to PySide

from pivy.

Comments (21)

looooo avatar looooo commented on May 24, 2024

@InventorMentor : is shiboken available in windows?
import shiboken
For me this works with conda, but not with apt-get. And I have no SoQt available with conda, so I can't try this.

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

Shiboken should be available for Windows with Python3, please cf.
https://pypi.python.org/pypi/Shiboken/1.2.2
and also
https://wiki.qt.io/PySide_Shiboken_Tutorial
To this end, I don't have any experience binding C++ code to Python, neither using SIP, Shiboken, or otherwise.

SIP, however, already comes preinstalled with WinPython, my favorite Python distribution for Windows.
Alternatively, it is also available from here:
https://pypi.python.org/pypi/SIP/4.19.2
Therefore, I suggest that I for my part attempt to go down the SIP-route trying to port the current Pivy-SoQt-binding from PyQt4 to PySide by adapting the following two files
pivy/Inventor/Qt/SoQtRenderArea.i
and
pivy/interfaces/soqt.i

So long, best wishes!

from pivy.

looooo avatar looooo commented on May 24, 2024

I have tried to port the SoQt-lib to pyside, but haven't tested it yet.
A problem is the availability of shiboken:
with pip: import Shiboken.shiboken
with conda: import shiboken
I have tried to add this at c-level, but I have no idea if this works.

Here is the branch: https://github.com/looooo/pivy/tree/soqt-port
looooo@d20aa69

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

Many thanks indeed! I'm on my way building Shiboken-1.2.2 on Windows 10 using msvc14. Apparently, Python 3.6 is not yet officially supported by Shiboken-1.2.2, nevertheless, considering issue
pyside/Shiboken#77 renaming subprocess.mswindows to subprocess._mswindows in file popenasync.py (twice) seems to do the trick. I'll see how I get on. So long.

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

After installing CMake (3.8.0 x64), fixing the above two lines and running
python.exe setup.py bdist_wheel --qmake=c:\Qt\4.8.7_msvc14\bin\qmake.exe
I also had to insert a missing msvc14 preprocessor definition as a workaround _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS in line 50 of file Shiboken-1.2.2\sources\shiboken:

if(MSVC)
    set(CMAKE_CXX_FLAGS "/Zc:wchar_t- /GR /EHsc /DWIN32 /D_WINDOWS /D_SCL_SECURE_NO_WARNINGS /D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS")

That finally built me Shiboken-1.2.2-cp36-cp36m-win_amd64.whl. After its pip installation, I can now happily import Shiboken.shiboken in Python 3.6 on Windows 10. Tomorrow or later today, I look forward to checking out your soqt-port. Best wishes!

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

Trying to run the following SoQtExaminerViewer.py:

import sys
from pivy.coin import *
from pivy.gui.soqt import *

# Initialize Coin (returns main window to use)
# If unsuccessful, exit.
myWindow = SoQt.init(sys.argv[0])
if myWindow == None: sys.exit(1)
# Make a scene containing a red cone.
myMaterial = SoMaterial()
myMaterial.diffuseColor = (1.0, 0.0, 0.0)
scene = SoSeparator() 
scene.ref()
scene.addChild(myMaterial)
scene.addChild(SoCone())
# Create a viewer to visualize our scene.
viewer = SoQtExaminerViewer(myWindow)
# Put our scene into viewer, change the title.
viewer.setSceneGraph(scene)
viewer.setTitle("Examiner Viewer")
viewer.show()
SoQt.show(myWindow)
SoQt.mainLoop()

I still receive a crash in trying to create a
viewer = SoQtExaminerViewer(myWindow)

I reckon that the legacy soqt.i implementation (being hard-coded for 32-bit platforms back then) is asking nowadays for trouble on 64-bit systems by throwing away half of the unsigned 64 bit address.
e.g. when casting

ptr = (QWidget*)PyLong_AsLong(address);

A C/C++ "long" is on most 64 platforms a "32 bit signed int", so an "unsigned long long" (address as uint64) would be needed instead. Therefore, I've already tried to modify your ported "soqt.i" in several places when converting pointers to something as in

ptr = (QWidget*)PyLong_AsVoidPtr(address);

C99 "stdint.h" / C++11 "cstdint" provide "uintptr_t" which gives the correct pointer type for the current platform (32 bit or 64 bit, respectively). I have been guessing that this is encapsulated by PyLong_AsVoidPtr but am not sure about this, whether a PyLong in Python3 is actually long enough using this conversion.

Anyhow, with or without this modification trying both the original "sip" or your "shiboken" version of Pivy-SoQt, I still get an

Unhandled exception at 0x00007FFCD61F5B33 (_soqt.cp36-win_amd64.pyd) in python.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
on win64. Is the SoQt example above actually working for you on linux64?

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

A slight correction to my post above:
The modfied (shiboken) version from your branch "soqt-port" crashes for me with the exception above in the last line of the example, when entering SoQt.mainLoop(). The legacy (sip) version so soqt.i, however, already crashes with the exception above in line viewer = SoQtExaminerViewer(myWindow).

from pivy.

looooo avatar looooo commented on May 24, 2024

No it doesn't run on linux. I have problems with importing shiboken.
this little example already fails for me on linux (python2)

import sys
from pivy import coin
from pivy.gui import soqt
import Shiboken

appWindow = soqt.SoQt.init(sys.argv[0])
print(appWindow)
viewer = soqt.SoQtRenderArea(appWindow)
print(viewer)
<PySide.QtGui.QWidget object at 0x7fe563ec6950>
Traceback (most recent call last):
  File "minimal.py", line 8, in <module>
    viewer = soqt.SoQtRenderArea(appWindow)
  File "/usr/local/lib/python2.7/dist-packages/pivy/gui/soqt.py", line 2548, in __init__
    this = _soqt.new_SoQtRenderArea(parent, name, embed, mouseInput, keyboardInput)
NotImplementedError: Wrong number or type of arguments for overloaded function 'new_SoQtRenderArea'.
  Possible C/C++ prototypes are:
    SoQtRenderArea::SoQtRenderArea(QWidget *,char const *,SbBool,SbBool,SbBool)
    SoQtRenderArea::SoQtRenderArea(QWidget *,char const *,SbBool,SbBool)
    SoQtRenderArea::SoQtRenderArea(QWidget *,char const *,SbBool)
    SoQtRenderArea::SoQtRenderArea(QWidget *,char const *)
    SoQtRenderArea::SoQtRenderArea(QWidget *)
    SoQtRenderArea::SoQtRenderArea()

As you can see the appWindow is a PySide-object, so therfore it got wrapped. But the SoQtRenderArea is not happy with the PySide widget. So I think there must be something wrong in the %typemap(in) QWidget{

commenting out the shiboken import however is working but the qt-objects are not wrapped:

from pivy import coin
from pivy.gui import soqt
# import Shiboken

appWindow = soqt.SoQt.init([])
print(appWindow)
viewer = soqt.SoQtRenderArea(appWindow)
print(viewer)
<pivy.gui.soqt.QWidget; proxy of <Swig Object of type 'QWidget *' at 0x7f777281da20> >
<pivy.gui.soqt.SoQtRenderArea; proxy of <Swig Object of type 'SoQtRenderArea *' at 0x7f77709f9090>

This let me think there must be something wrong with the shiboken import on c++-side, which looks like this:

static PyObject* getShiboken()
{
  PyObject *shiboken;
  // if the shiboken module is already loaded 
  shiboken = PyDict_GetItemString(PyModule_GetDict(PyImport_AddModule("__main__")), "shiboken");
  if (shiboken){
    return shiboken;
  }
  else {
    /* try to import shiboken */
    shiboken = PyImport_ImportModule("shiboken");
    if (shiboken){
      Py_INCREF(shiboken);
      return shiboken;
    }

    /* for pip installed shiboken */
    shiboken = PyImport_ImportModule("Shiboken.shiboken");
    if (shiboken){
      Py_INCREF(shiboken);
      return shiboken;
    }
  }
  return shiboken;
}

from pivy.

looooo avatar looooo commented on May 24, 2024

wrong button ;-)

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

On Win64-Py3.6, your above example ran fine for me without commenting out "import Shiboken". It printed out the following:
<pivy.gui.soqt.QWidget; proxy of <Swig Object of type 'QWidget *' at 0x000002071770ED50> >
<pivy.gui.soqt.SoQtRenderArea; proxy of <Swig Object of type 'SoQtRenderArea *' at 0x0000020717180CF0> >

from pivy.

looooo avatar looooo commented on May 24, 2024

strange.
I think I found one problem:
shiboken.getCppPointer(obj) != sip.unwrapinstance(obj) therfor the typemap_in doesn't work.

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

In my version of your branch, I've replaced in file soqt.i
PyLong_AsLong(address) --> PyLong_AsVoidPtr(address)
Does this explain the difference?

from pivy.

looooo avatar looooo commented on May 24, 2024

The difference of shiboken and sip is the return type:
sip.unwrapinstance(obj) -> integer
shiboken.unwrap(obj) -> tuple (where the first element is the adress)

I have already applied your patch, thanks.

ps.: I will upload a new branch soon. I have experimented alot with the imports... Maybe this is the reason for the different behaviors.

from pivy.

looooo avatar looooo commented on May 24, 2024

I think with the last commit the typemap_in does work. At least I have no problem with running the examples with and without importing shiboken. Actually shiboken isn't really necessary for creating a soqt viewer. But then there is no interaction with qt possible. Importing shiboken in python wraps the viewer correctly. But I think importing shiboken in python shouldn't be necessary.

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

Thank you very much indeed for your most valueable contribution! Using your commit ea5ed40, I now can successfully run my little example above (SoQtExaminerViewer.py) using Win64-Python36. The availability of an SoQt binding under Python3 makes me really happy, since I think using SoQt might work around the few open issues with the Inventor Mentor examples that remain with Pivy's QuarterWidget. I look forward to checking this out in the next couple of days. Thanks again and have a nice day!

from pivy.

looooo avatar looooo commented on May 24, 2024

this is now in master. thanks for the help.

from pivy.

looooo avatar looooo commented on May 24, 2024

reopen this as 10.2 does not work.

Traceback (most recent call last):
  File "10.2.setEventCB.py", line 148, in myAppEventHandlerQt4
    if anyevent.buttons() == Qt.LeftButton:
AttributeError: 'PySide.QtCore.QEvent' object has no attribute 'buttons'

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

With the following modified example 10.2

###
#  This is an example from The Inventor Mentor
#  chapter 10, example 2.
#
#  This demonstrates using SoGuiRenderArea::setEventCallback().
#  which causes events to be sent directly to the application
#  without being sent into the scene graph.
#  
# Clicking the left mouse button and dragging will draw 
#       points in the xy plane beneath the mouse cursor.
# Clicking middle mouse and holding causes the point set 
#       to rotate about the Y axis. 
# Clicking right mouse clears all points drawn so far out 
#       of the point set.
#

import sys

import sys
from pivy.coin import *
from pivy.gui.soqt import *

# Timer sensor 
# Rotate 90 degrees every second, update 30 times a second
myTicker = None
UPDATE_RATE    = 1.0/30.0
ROTATION_ANGLE = M_PI/60.0

def myProjectPoint(myRenderArea, mousex, mousey):
    # Take the x,y position of mouse, and normalize to [0,1].
    # X windows have 0,0 at the upper left,
    # Inventor expects 0,0 to be the lower left.
    size = myRenderArea.getSize()
    x = float(mousex) / size[0]
    y = float(size[1] - mousey) / size[1]
   
    # Get the camera and view volume
    root = myRenderArea.getSceneGraph()
    myCamera = root.getChild(0)
    myViewVolume = myCamera.getViewVolume()
   
    # Project the mouse point to a line
    p0, p1 = myViewVolume.projectPointToLine(SbVec2f(x,y))

    # Midpoint of the line intersects a plane thru the origin
    intersection = (p0 + p1) / 2.0

    return intersection

def myAddPoint(myRenderArea, point):
    root = myRenderArea.getSceneGraph()
    coord = root.getChild(2)
    myPointSet = root.getChild(3)
   
    coord.point.set1Value(coord.point.getNum(), point)
    myPointSet.numPoints = coord.point.getNum()

def myClearPoints(myRenderArea):
    root = myRenderArea.getSceneGraph()
    coord = root.getChild(2)
    myPointSet = root.getChild(3)
   
    # Delete all values starting from 0
    coord.point.deleteValues(0) 
    myPointSet.numPoints = 0

def tickerCallback(myCamera, sensor):
    mtx = SbMatrix()

    # Adjust the position
    pos = myCamera.position.getValue()
    rot = SbRotation(SbVec3f(0,1,0), ROTATION_ANGLE)
    mtx.setRotate(rot)
    pos = mtx.multVecMatrix(pos)
    myCamera.position = pos

    # Adjust the orientation
    myCamera.orientation.setValue(myCamera.orientation.getValue() * rot)
    
###############################################################
# CODE FOR The Inventor Mentor STARTS HERE  (part 1)

def myAppEventHandler(myRenderArea, anyevent):
    handled = TRUE

    if anyevent.type() == QEvent.MouseButtonPress:
        if anyevent.button() == QMouseEvent.LeftButton:
            vec = myProjectPoint(myRenderArea, anyevent.x(), anyevent.y())
            myAddPoint(myRenderArea, vec)
        elif anyevent.button() == QMouseEvent.MidButton:
            myTicker.schedule()  # start spinning the camera
        elif anyevent.button() == QMouseEvent.RightButton:
            myClearPoints(myRenderArea)  # clear the point set

    elif anyevent.type() == QEvent.MouseButtonRelease:
        if anyevent.button() == QMouseEvent.MidButton:
            myTicker.unschedule()  # stop spinning the camera

    elif anyevent.type() == QEvent.MouseMove:
        if anyevent.state() == QMouseEvent.LeftButton:
            vec = myProjectPoint(myRenderArea, anyevent.x(), anyevent.y())
            myAddPoint(myRenderArea, vec)

    else:
        handled = FALSE

    return handled

def myAppEventHandlerQt4(myRenderArea, anyevent):
    handled = TRUE

    if anyevent.type() == QEvent.MouseButtonPress:
        if anyevent.button() == Qt.LeftButton:
            vec = myProjectPoint(myRenderArea, anyevent.x(), anyevent.y())
            myAddPoint(myRenderArea, vec)
        elif anyevent.button() == Qt.MidButton:
            myTicker.schedule()  # start spinning the camera
        elif anyevent.button() == Qt.RightButton:
            myClearPoints(myRenderArea)  # clear the point set

    elif anyevent.type() == QEvent.MouseButtonRelease:
        if anyevent.button() == Qt.MidButton:
            myTicker.unschedule()  # stop spinning the camera

    elif anyevent.type() == QEvent.MouseMove:
        if anyevent.buttons() == Qt.LeftButton:
            vec = myProjectPoint(myRenderArea, anyevent.x(), anyevent.y())
            myAddPoint(myRenderArea, vec)

    else:
        handled = FALSE

    return handled

# CODE FOR The Inventor Mentor ENDS HERE
###############################################################

def main():
    global myTicker
    
    # Print out usage instructions
    print("Mouse buttons:\n"
          "\tLeft (with mouse motion): adds points\n"
          "\tMiddle: rotates points about the Y axis\n"
          "\tRight: deletes all the points")

    # Initialize Inventor and Qt
    appWindow = SoQt.init(sys.argv[0])
    if appWindow == None:
        sys.exit(1)

    # Create and set up the root node
    root = SoSeparator()

    # Add a camera
    myCamera = SoPerspectiveCamera()
    root.addChild(myCamera)                 # child 0
   
    # Use the base color light model so we don't need to 
    # specify normals
    myLightModel = SoLightModel()
    myLightModel.model = SoLightModel.BASE_COLOR
    root.addChild(myLightModel)             # child 1
   
    # Set up the camera view volume
    myCamera.position = (0, 0, 4)
    myCamera.nearDistance = 1.0
    myCamera.farDistance = 7.0
    myCamera.heightAngle = M_PI/3.0
   
    # Add a coordinate and point set
    myCoord = SoCoordinate3()
    myPointSet = SoPointSet()
    root.addChild(myCoord)                  # child 2
    root.addChild(myPointSet)               # child 3

    # Timer sensor to tick off time while middle mouse is down
    myTicker = SoTimerSensor(tickerCallback, myCamera)
    myTicker.setInterval(UPDATE_RATE)

    # Create a render area for viewing the scene
    myRenderArea = SoQtRenderArea(appWindow)
    myRenderArea.setSceneGraph(root)
    myRenderArea.setTitle("My Event Handler")

###############################################################
# CODE FOR The Inventor Mentor STARTS HERE  (part 2)

    # Have render area send events to us instead of the scene 
    # graph.  We pass the render area as user data.

    if SoQt.getVersionToolkitString().startswith('4'):
        myRenderArea.setEventCallback(myAppEventHandlerQt4, myRenderArea)
    else:
        myRenderArea.setEventCallback(myAppEventHandler, myRenderArea)

# CODE FOR The Inventor Mentor ENDS HERE
###############################################################

    # Show our application window, and loop forever...
    myRenderArea.show()
    SoQt.show(appWindow)
    SoQt.mainLoop()

if __name__ == "__main__":
    main()

there is still a remaining issue with C++ type-resolution when trying to call overloaded member function SoQtRenderArea::setEventCallback in SoQt from pivy/gui/soqt.py", line 2611 (using msvc14, win64, py36, Qt-4.8.7, SoQt-1.5.0):


Traceback (most recent call last):
  File "C:/opt/libs/pivy-0.6.0/examples/Mentor_SoQt/10.2.setEventCB.py", line 207, in <module>
    main()
  File "C:/opt/libs/pivy-0.6.0/examples/Mentor_SoQt/10.2.setEventCB.py", line 194, in <module>
    myRenderArea.setEventCallback(myAppEventHandlerQt4, myRenderArea)
  File "C:\WinPython\python-3.6.1.amd64\Lib\site-packages\pivy\gui\soqt.py", line 2611, in setEventCallback
    return _soqt.SoQtRenderArea_setEventCallback(self, func, user)
builtins.NotImplementedError: Wrong number or type of arguments for overloaded function 'SoQtRenderArea_setEventCallback'.
  Possible C/C++ prototypes are:
    SoQtRenderArea::setEventCallback(SoQtRenderAreaEventCB *,void *)
    SoQtRenderArea::setEventCallback(SoQtRenderAreaEventCB *)

from pivy.

looooo avatar looooo commented on May 24, 2024

would it be possible to do the work directly on the file and upload to a fork on github? this would make it easier for me to see the difference. + You have the possibility to work on pivy directly via pull-requests.

from pivy.

InventorMentor avatar InventorMentor commented on May 24, 2024

Fine, forking your current repository and running example 10.2,
now gives me an error in line 133, in myAppEventHandlerQt4:
AttributeError: 'QEvent' object has no attribute 'type'

line 133: if anyevent.type() == QEvent.MouseButtonPress:

If I insert the statement print(anyevent) before that line, anyevent is printed as:
<pivy.gui.soqt.QEvent; proxy of <Swig Object of type 'QEvent *' at 0x00000187BBBAA8D0> >

from pivy.

looooo avatar looooo commented on May 24, 2024

I close this issue and create a new one for this specific example.

from pivy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.