Saturday 27 October 2012

A busy-ish week. Further work on CAM Plugins

The week's been a busy one with Group Project work at University - having way too many meetings, that haven't resulted in a great outcome.


Work on the CAM Module (no pretty pictures):


This post is in reference to recent commit history in the CAM developer branch


Nevertheless there are has been a few more opportunities to work on the CAM module.  The Cam Objects have been tweaked so that the Tool Path Generators are automatically updated when there is change to the Part Geometry and the Stock Geometry material. This is useful for obvious reasons so that the whole Cam Feature will automatically update itself and along with this the resultant GCode rather than having to manually calculate all the features again.

The next step was attempted to integrate a Cam Library - libarea-clipper into the source tree and make the python bindings available for other python modules within FreeCAD. This was only really good practice learning how to play with CMake configuration files, that's all, but the end result is that our TPG's can now use this library if they are c++ or python!

Work also began on working on the TPGFactory methods for essentially loading all the TPG's if they are c++ based or Python based.

C++ was pretty straight forward going where we can interact with the TPG and TPGFeature very easily.

Python requires making an extension using boost::python. This has its set of many difficulties and still has alot of work to get done but in practice it does work.

One stumbling point was that for TPGPython our c++ python extension to be loaded into Python, we have to put this in a seperate dynamic library. Frustratingly this took some time to realise and required numerous changes to the CMakeLists.txt file - the build configuration script we use.

Another painful learning experience was figuring out why the virtual method run()  was not being called. This virtual method is defined inside python and are later called. The first thing I forgot was define the callback - see here and I had implemented the run method in TPGPython which created a conflict. Finally atleast we have an interesting message when we call the run method()

I've also implemented the file search function that looks for .tpg files within a directory and is recursive too.

There's still a lot more work to do, but things are coming together fairly nicely. My apologies if this post hasn't made  much sense.

Sunday 21 October 2012

Help for creating C++ Modules in FreeCAD

Being slightly hungover from a crazy night out, I figured I might aswell try and doing something useful, so I am going to try and explain the structure for implementing a structure using c++ in FreeCAD.

It's useful to understand this to build a clear logical  structure rather than a mashup, which makes it more easy to document improving accessible for people to understand how the module fits together and get them developing! That's one of the reason's I'm not a big fan of using python solely in FreeCAD modules...

The App & GUI:

FreeCAD is essentially built around two core areas - the application code and the GUI which is essential for users to get something productive out of the program. 

Application:

The application provides the facility to perform operations, calculations, managethe document structure and its features. It's built around numerous libraries, the obvious one being OpenCascade which provides the modelling features. The application should be usable without a GUI so it behaves like a console application. 

FreeCAD comprehensivly uses python throughout to give greater power to users and ease development. It's very easy for the users to run commands in the python interpreter. Even still the application code can still execute python commands which are typically used for creating / editing features but quite essential for enabling the undo-redo system to work.

Any GUI related libraries cannot be used in the application module, however, we can still use some modules from QT as part of the application modules, such as:

  • QTCore
  • QTNetwork
  • QTXML

The Gui

The GUI is infact optional, and this can be ommited whilst compiling. This eventually give us greater flexibility in terms of the user interaction. For example we could in theory build a WebGL version of FreeCAD.

The GUI uses the Coin3D for managing the OpenGL Scenegraph based on the Open Inventor whilst we use Qt4 for providing the overall application user interface. These are linked together using SoQtViewer. 

Building a Structure:

I always recommend to look at the Sketcher Module which despite it's complexity is a classic example of how a c++ module should look.

It's best to seperate the module into two seperate folders atleast, the App and the GUI folder. This helps prevent cross contamination of GUI code into the application code. 

Below is simple diagram explaining how the structure fits together.



Each module will have it's own Features and potentially sub features too. Depending on the complexity of the feature, these features should only provide an interface (python) to another class which is intialised as a protected member and is callable. This keeps the document feature easier to work with and keeps the main functions are processes isolated together. Usually I create a seperate subfolder in the app directory to keep these classes together.

Each document feature declares a string to a specified viewprovider - defined in

const char* getViewProviderName() const 

This allows FreeCAD to load the viewprovider if there is a GUI interface. Each View Provider is assigned a pcObject which references the document feature that it is assigned to. other gui elements have to be implemented such as command.cpp, workbench and if needed the taskdialog and its taskboxes.

Document Objects / Features:

Each Module will have to define its own document feature, this is achieved by inheriting from App::DocumentObject.  There are many virtual class members that can be overriden. Each Feature has then several properties that can be used to store such as
  • Integers (App::PropertyInteger)
  • Floats (App::PropertyFloat)
  • Strings (App::PropertyString)
  • Lists
  • Links (App::PropertyLink)
  • SubLinks (App::PropertySubLink)  - a link to a feature and with a sub reference (e.g. a face, or edge on a part)
Including these makes life much simpler for the programmer; we don't have to worry about undo-redo mechanism and saving and restoring these into the document. We can also define our own properties but this introduces further complexities and should tried to be avoided.

We can link together other features using links and this introduces a dependency. When the sub feature is touched - its properties have changed, the parent feature will update itself accordingly. We can control this behaviour by re-implementing the following methods

  • void onBeforeChanged(const App::Property* /*prop*/)
  • void onAfterChanged(const App::Property* /*prop*/)
  • void onChanged(const App::Property* /*prop*/)
  • short mustExecute() const;
The main calculations or functions are perfomed in

App::DocumentObjectExecReturn *execute(void);

these are called when the recompute method is called either for the document feature or the whole document.

A document feature can also be implemented to take advantage of python. This requires defining an XML file and then implementing the generating functions in a myFeaturePyImp.cpp file. Generally an argument list is parsed and then if valid the correct c++ functions are called in the document feature. 

ViewProviders

ViewProviders provide the majority of the interface for a document feature. It manages the object's presentation and manipulation in the 3D view by allowing the developer to manipulate the Coin3D scenegraph. Also it defines how the feature is handled and presented in the Document Tree.

ViewProviders inherit from Gui/ViewProvider.h but can also inherit from other ViewProvider classes to obtain already defined behaviours. There aren't any members that need to be defined but it makes sense that you do.

GUI::Commands

These are basically commands that are registered in the GUI application that can be called by tool bar icons or the main menus. These can be programmed with a lot of logic during the prototyping phase, but it's not recommended that they are simple commands which will use the python interface.

 The things to remember:

  • Seperate your module into Application and GUI
  • Keep your Document Features as interfaces
  • Use App::Properties to save you time
  • Seperate processes and calculations into seperate classes
  • Keep Things Simple At First - get your module working and build up

Friday 19 October 2012

2000 Reads and Quick Guide to connecting Boost Signals

Well to say I only started this blog in summer, I'm pretty impressed to reach 2000 reads. Atleast someone must find my writing useful. Further work continues on refining the structure of the CAM module. Things are going reasonably well and each piece of the jigsaw is coming together.

I also stumbled on a little GEM on the forums after I was having problems creating the Document Objects that have children, for example like this hierarchy below...



If we delete ToolPaths using the GUI, ideally we want the children (TPGFeature) to be delete accordingly. Inheriting from a App::DocumentObject we do not get such a luxury.

Solution - Using Boost::Signals:

We need to set up an signal/slot mechanism using the Boost Libraries to observe when a document object is deleted.These are pretty simple to use and remove the need for having to use QT and it's signal/slot mechanism that requires inheriting from QObject and run through the MOC preprocessor. This is fine in context of the GUI interface, but isn't necessary in the rest of the application.

Boost signals are pretty straightforward to use:

In the class header file we need to include these. Essentially the typedef is just a typing shortcut to make the syntax less cumbersome to write.
#include <boost/signals.hpp>
typedef boost::signals::connection Connection;
In the class declaration we need a Connection member delObjConnection and this slot function that will be called when a signal is intercepted. In our case, when the signalDeletedObject is made within our slot function onDelete we need to have a App::DocumentObject as parameter. This slot function has to be public.
public:
    ///SLOTS
    void onDelete(const App::DocumentObject &docObj);
protected:
    ///Connections
    Connection delObjConnection;
In the class definition, we now need to set up our connection and also implement our slot. The function onSettingDocument overrides the implementation in App::DocumentObject. This is called just after the CamFeature object has been constructed and has a document assigned to it. (This was only recently added in the GIT master)

CamFeature::~CamFeature()
{
    delObjConnection.disconnect();
}

void CamFeature::onSettingDocument()
{
    //Create a signal to observe slot if this item is deleted
    delObjConnection = getDocument()->signalDeletedObject.connect(boost::bind(&Cam::CamFeature::onDelete, this, _1));
}

That's pretty much it. Now we can delete child objects in the onDelete slot we have made!

Wednesday 17 October 2012

Cam Module - Work over the Weekend

Git Repo:

I have created a GIT Repo on github that the other guys are going to push back their changes to, so look here if you're interested in seeing our progress.

Weekend Work:

I spent the last weekend laying the ground work structure for the FreeCAD Cam Module - inadvertently helped by my student house mates being away, making it calm around here. Essentially the hardest or laborious task was creating the source structure. There are several classes which require both the declaration and definition just to work. This leads to a file tree in the module like so:


And there's more GUI stuff too!

This was created based on the design document we created over last week outlining a proposal for how all this stuff could fit together.



The Dependency Graph:

FreeCAD has a fairly intelligent system of managing updates through the document. Each document object can be referenced by a series of links which behave as dependency. When a Document Object changes or it's property. When this happens the property or Document Object is 'touched' and this indicates it should be recompute the hierarchy tree.



Any dependencies that reference this object will automatically be requested to recompute and update themselves. This is what drives parametric design but being transparent to the developer.

The first attempt at fitting these classes together wasn't entirely successful and in its process also made the discovery of some good fixes in the base FreeCAD application. The end result for the dependency chart (below) for the structure seemed logical but introduced several difficulties.


Logically the structure makes sense in terms of the object hierarchy. However, for the program it doesn't. When the StockGeometry, or CamPartList features update, the tool paths will not automatically update. It took me two hours to figure that one out and it didn't look pretty. Boo hoo.

I had two beers and a night off to think about this on Sunday. It became apparent that the CamFeature was simply a top level container that would provide a general interface for accessing and managing the other features - it didn't control the actual CAM process.

Instead I created an object hierarchy like so. Essentially GCodeFeature is the result from the combined results of the TPG. However we get the all the glorious updating mechanism with this.


The ToolPaths manages the Input and controls the process of updating the TPGFeatures eventually more intelligently.

The TPGFeatures are quite dumb. They behave like blackboxes and are given an input, do their thing and spit back a result. The nice thing is thing about this it will allow new TPG's to be more quickly developed since the developers don't have to set up the document feature, but only have to provide the input and in return can get the GCode back.

Sunday 14 October 2012

CAM Module

FreeCAD CAM Module.  Take 2:

After a fair bit of discussion through the Google Docs, Blog Entries, Forum Posts and ofcourse some IRC chatting Ideas we have pushed again and started the CAM 2 Module. Perhaps it's incorrect to say CAM2 but we are definitely putting the new source files in a new folder since we are essentially starting from scratch. We have even been blessed with a new subheading on the FreeCAD forums.

Objectives for this Module:

Essentially we aim to integrate the whole CAM workflow into FreeCAD.  The tool algorithms are developed  already in many libraries and are already useful but there is no practical integration within FreeCAD.


Secondary Objective : To cut out Sliptonic's spider!

The rough workings of CAM from a newbie:

The module will take your 3D Part within FreeCAD as the primary input. We provide a set process this with tooling algorithms which generates machine instructions (tool paths) known as GCODE. These are post-processed manually by the user and can be visualised within FreeCAD to check for any problems. We are basing a lot of the design on the work already achieved by HeeksCNC.

CAM in this Module will be a subtractive process -we remove material from a piece of Stock - such as sheet of steel by a series of operations. Each operation will be generated by a TPG - a Tool Path Generator. These are plugins which can be written in c++, python perhaps other languages and use their own algorithms to generate paths for the CAM Machine to remove material. These TPGs aim to be flexible, so we can call a  process to proprietary application allow this to do the hard work and then import it back into FreeCAD, but this process being entirely transparent. 

How I fit into this:

The strangest experience with this side project is that I have very little practical knowledge and experience working with CAM so I am very reliant on the wisdom of our CAM experts who have set up their requirements and how the perceive it working within FreeCAD. This is what makes it interesting in respect but also a difficult task. It is good practice working in an environment like this because I still yet to find a job that involves team work at such level haha.

My role in this project is to try and build up the basic FreeCAD infrastructure and then this will allow the other developers such as awallin, arobinson, dfalck to work on this independently, integrating the tools in.

Additionally work to build an awesome GUI interface into this ofcourse!

Saturday 6 October 2012

Back to University. Back to FreeCAD. Updates

After my intermission of going on holiday in Europe (if you could call it that) , I am now back at University and have some free time to work on FreeCAD.

Coding Improvements to the Render Module:

The past few days I've tidied up the Render Module and improve the QML code to improve the quality of the UI presentation. In addition I have now implemented the saving and restoration of material properties, so this means for example you can save the 'colour' within the Matte material.

During mid-September inside the Render Module, I tidied up some QT and Coin3D GUI dependencies that existed in the core application functionality. These were trivial changes and other small coding improvements were made to the Render Module.

Building on Windows:

To give the Render Module a greater spectrum of Testers, we would like to get the Render Module compile on Windows. Work was done to implement class definitions that were missing.

There was a brief discussion on building using QT 4.5/ QT 4.6, which the current Windows Libpack includes. Unfortunately this doesn't include QML or/ QtDeclarative Modules, therefore it isn't possible to build the render module on Windows yet. In practice this means that the Render Module will not be available till the 0.14 release, when we can guarantee that most Linux distributions will include this. However, this will give another 6 months of testing to ensure that this module contains more features and improve the quality through testing.

GIT Housekeeping:

Having been working solely on the Render Module over the past three months, in my own ignorance, I have refrained from keeping an updated revision of the FreeCAD source. I've now forked and cloned from the FreeCAD source mirror on github and have set up a new repository and merged the Render Module into a new branch:

This somewhat both complicates and simplifies keeping upto date with the FreeCAD repository and there is always the added difficulty of learning something new!

CAM Module:

I am looking into helping start an initiative to implement CAM functionality into FreeCAD with guidance from Daniel Falck and Brad Collette. Currently trying to work out how this system will work and draw up a structure for this. I will report back on this in short time.