GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Have some feature requests, feedback, cool stuff to share, or want to know where FreeCAD is going? This is the place.
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
ickby
Posts: 2978
Joined: Wed Oct 05, 2011 7:36 am

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby ickby » Wed Jul 15, 2020 9:13 am

Nice work!

One remark: You currently hard coded the scene structure of a object into your code, where exactly the individual nodes are. This does only work for Part objects, as only those use this exact structure. Any other visualisation could use any kind of structures. Hence it makes sense to change your implementation to be more generic.

Coin works by iterating the scene graph and storing the "last seen nodes" to use them when needed. E.g. it goes down the graph, and when it finds a Coordinate3 node it stores it as currently active Coordinate Node. When it afterwards encounters any node, that requires a Coordinate3 node (like IndexedFaceSet), it uses the last seen one it has stored. If it encounteres another Coordinate3 node it overrides the currently active Coordinate3 node.
Implementing a system like this in your code gives you the possibility to parse all possible scene graphs.
User avatar
yorik
Site Admin
Posts: 12011
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels, Belgium
Contact:

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby yorik » Thu Jul 16, 2020 12:19 pm

Great progresses @kryptokommunist ! It's great to see all the chain from FreeCAD to WebGL debunked step by step...
At some point, it would be cool if you could have a look at the current FreeCAD to WebGL exporter at https://github.com/FreeCAD/FreeCAD/blob ... rtWebGL.py
an maybe see how we could use your work there... I have the impression you'll get to a better result, plus yours is working without the GUI open, which is definitely more interesting
User avatar
kryptokommunist
Posts: 68
Joined: Fri Mar 27, 2020 6:29 pm
Location: Berlin
Contact:

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby kryptokommunist » Thu Jul 16, 2020 10:31 pm

I thought extracting the camera from the scene graph would make sense, so we get the same defaults as in FreeCAD. But after searching through the code and looking at the scene graph I can't find where the camera view is defined. To me it looks like the camera view is set somewhere outside the scene graph since when I open FreeCAD and create a document with an object the following code inside the Python console doesn't find any node inside the scene graph that is camera related:

Code: Select all

>>> from pivy import coin
>>> def dfs_traversal(root_node):
...         for node in root_node:
...             if "Camera" in str(type(node)):
...                 print("Found camera node: {}".format(type(node)))
...             if type(node) is coin.SoSeparator or type(node) is coin.SoSwitch:
...                 dfs_traversal(node)
... 
>>> sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()
>>> dfs_traversal(sg)
>>>
It should identify any Camera node since this part of the code works:

Code: Select all

>>> "Separator" in str(type(sg))
True
>>> str(type(sg))
"<class 'pivy.coin.SoSeparator'>"
The same holds true for "Light". Are the lighting and camera settings hidden in some special node? Alternatively I could just create some default settings myself.
Last edited by kryptokommunist on Fri Jul 17, 2020 8:17 am, edited 1 time in total.
User avatar
kryptokommunist
Posts: 68
Joined: Fri Mar 27, 2020 6:29 pm
Location: Berlin
Contact:

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby kryptokommunist » Thu Jul 16, 2020 10:36 pm

ickby wrote:
Wed Jul 15, 2020 9:13 am
This does only work for Part objects, as only those use this exact structure. Any other visualisation could use any kind of structures. Hence it makes sense to change your implementation to be more generic.
I'm on it!

yorik wrote:
Thu Jul 16, 2020 12:19 pm
At some point, it would be cool if you could have a look at the current FreeCAD to WebGL exporter at https://github.com/FreeCAD/FreeCAD/blob ... rtWebGL.py
an maybe see how we could use your work there...
That should be not that far away. With the current code we can extract an threejs scene graph in JSON right from the Coin3D graph and then package that with some Javascript and HTML. That way we could save not just objects but it should also be possible to e.g. save the visual output of a FEM analysis. But I haven't tested that yet.

Reading into the WebGL export code it seems to extract the faces from Mesh::Feature instead of the Coin3D graph. Is there any difference? Then it builds Javscript by creating Strings within Python. My approach looks a bit cleaner since I now use Pythreejs to do the dirty work of translating it.
Last edited by kryptokommunist on Fri Jul 17, 2020 2:26 pm, edited 2 times in total.
User avatar
yorik
Site Admin
Posts: 12011
Joined: Tue Feb 17, 2009 9:16 pm
Location: Brussels, Belgium
Contact:

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby yorik » Fri Jul 17, 2020 12:17 pm

kryptokommunist wrote:
Thu Jul 16, 2020 10:36 pm
Reading into the WebGL export code it seems to extract the faces from Mesh::Feature instead of the mono]Coin3D[/mono] graph. Is there any difference? Then it builds Javscript by creating Strings within Python. My approach looks a bit cleaner since I now use Pythreejs to do the dirty work of translating it.
Your approach is definitely cleaner :D

That code is pretty old and a bit hackish... Taking data directly from coin3D is of course better and has many more possibilities. Plus, color and material info are already defined, etc.FreeCADGui.ActiveDocument.ActiveView.getCamera()

Regarding the camera, you can get view camera info from FreeCADGui.ActiveDocument.ActiveView.getCamera() and FreeCADGui.ActiveDocument.ActiveView.getCameraNode() (also from FreeCADGui.ActiveDocument.ActiveView.getViewer() )
User avatar
bernd
Posts: 10702
Joined: Sun Sep 08, 2013 8:07 pm
Location: Zürich, Switzerland

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby bernd » Tue Jul 28, 2020 3:02 pm

kryptokommunist wrote:
Thu Jul 16, 2020 10:36 pm
but it should also be possible to e.g. save the visual output of a FEM analysis. That would surely be cool.
May be totally offtopic. I recently discovered jupyther notebook as quite useful for my daily work as structural engineer even without the use of FreeCAD. But ... Is it possible to test your work somehow without reading throught all the topic. Ist there some overview post how the bits and pieces fit together?
User avatar
kryptokommunist
Posts: 68
Joined: Fri Mar 27, 2020 6:29 pm
Location: Berlin
Contact:

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby kryptokommunist » Wed Jul 29, 2020 12:35 am

ickby wrote:
Wed Jul 15, 2020 9:13 am
One remark: You currently hard coded the scene structure of a object into your code, where exactly the individual nodes are. [...] Hence it makes sense to change your implementation to be more generic.
It is now implemented that way.

  • find out where in FreeCAD I can access the names of edges and surfaces
I still don't have a good solution for this.

  • extending my current pythreejs scene graph function to attach labels to it's surfaces and edges
Not started yet.

  • extract color, lines, camera, lighting correctly from the FreeCAD scene graph as there currently are still some issues
Last week I got bogged down with some issues with the pythreejs implementation. There were some bugs and even the example code for setting up lighting correctly for a geometry didn't work. After a while I realized that you need to compute vertex normals for lighting to work. Then I found out that the pythreejs way of doing that has a bug (just doesn't work, no error message though). These and some other small things with the other goals above added together were quite frustrating so I procrastinated a bit with my side project. Let's say I put in some more community bonding. But I apologize for not posting updates more recently and I hope to make up for this later. Anyways since I finally solved this my motivation is back again :geek: I think it's still realistic to finish this in the next month. (If not I will continue anyways)

On this point I still don't know if I can extract a camera and lighting source at all when running FreeCAD headless. If there are no remarks on that I'd like to understand what the default settings for FreeCAD are and just hard-code copy them.

normals.gif
normals.gif (663.41 KiB) Viewed 510 times
lighting_demo.gif
lighting_demo.gif (325.99 KiB) Viewed 510 times

My goals for this week are (kanban link)
  • find out where in FreeCAD I can access the names of edges and surfaces
  • extending my current pythreejs scene graph function to attach labels to it's surfaces and edges
  • hard copy default camera, lighting defaults from FreeCAD
Last edited by kryptokommunist on Wed Jul 29, 2020 7:02 pm, edited 1 time in total.
User avatar
kryptokommunist
Posts: 68
Joined: Fri Mar 27, 2020 6:29 pm
Location: Berlin
Contact:

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby kryptokommunist » Wed Jul 29, 2020 1:08 am

bernd wrote:
Tue Jul 28, 2020 3:02 pm
May be totally offtopic. [..] Is it possible to test your work somehow without reading throught all the topic. Ist there some overview post how the bits and pieces fit together?
No that's perfectly on topic. I'd be happy for someone to test this to find issues currently not on my radar. The faster way to start would be just running this notebook from the repo. I added some text to summarize, if there is still something missing please let me know.
User avatar
amrit3701
Posts: 303
Joined: Mon Jun 13, 2016 5:37 pm

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby amrit3701 » Wed Jul 29, 2020 3:11 pm

kryptokommunist wrote:
Wed Jul 29, 2020 12:35 am
normals.gif


lighting_demo.gif


My goals for this week are (kanban link)
  • find out where in FreeCAD I can access the names of edges and surfaces
  • extending my current pythreejs scene graph function to attach labels to it's surfaces and edges
  • hard copy default camera, lighting defaults from FreeCAD
Nice job @kryptokommunist 8-)
wmayer
Site Admin
Posts: 16294
Joined: Thu Feb 19, 2009 10:32 am

Re: GSoC 2020: A better IPython and Jupyter Notebook Integration for FreeCAD

Postby wmayer » Thu Jul 30, 2020 4:15 pm

find out where in FreeCAD I can access the names of edges and surfaces
Vertexes, edges and faces (sub-shapes) don't have explicit names. In FreeCAD we simply call them Vertex/Edge/Face and append a number. The number of a sub-shape is the key value associated to the sub-shape when storing it in a map (see e.g. TopoShapePy::getEdges). Like in most parts of OCCT the numbers start with 1, not 0.

Then on display side the logic is implemented in PartGui::ViewProviderExt and our custom Inventor nodes SoBrepPointSet, SoBrepEdgeSet and SoBrepFaceSet.
The mapping between a sub-shape on shape and rendering is handled with the two methods ViewProviderPartExt::getElement and ViewProviderPartExt::getDetail

The naming is part of the application logic and is not saved into an Inventor or VRML file.
hard copy default camera, lighting defaults from FreeCAD
Yes, there is indeed a "hidden" part of the actual scene graph. When you use the method getSceneGraph() of the 3d view (View3DInventorViewer) you get only a sub-part of the actual graph. To get the complete scene you must use the method getSceneGraph() of the SoRenderManager.

Code: Select all

from pivy import coin
view = Gui.ActiveDocument.ActiveView.getViewer()
scene = view.getSoRenderManager().getSceneGraph()

sa = coin.SoSearchAction()
sa.setType(coin.SoCamera.getClassTypeId())
sa.apply(scene)
sa.getPath().getTail()
while when using the view's scene graph you can't access the camera:

Code: Select all

from pivy import coin
view = Gui.ActiveDocument.ActiveView.getViewer()
scene = view.getSceneGraph()

sa = coin.SoSearchAction()
sa.setType(coin.SoCamera.getClassTypeId())
sa.apply(scene)
sa.getPath() # is None