Update 27th July 2017
With a PR complete, my efforts since the last update had been towards developing a simple implementation that gives sensible toponaming for a small set of Part::Features that would be useful. I chose Box, Boolean and Fillet because they had a way to define all faces (Box has Top, Bottom, Left, Right, Front, and Back, the others have it based on which faces/edges of the previous shapes(s) they were modified/generated from). For some shapes, like Cone, it appears OCC simply does not have a method to identify all sub shapes (for cone, only the lateral face)
In my previous post (on 14th), I had said I plan to use an implementation of TopoHistory that avoids storing BRepBuilderAPI_MakeShape, and I was using TNaming for that. Unfortunately, the approach suffers from 2 problems:
- We can only track modified subshapes. For example, in a prism P generated from a face F, if I feed in an edge E of F into the selector, Tnaming_Selector::Solve succeeds but only returns E as a part of P. Since there is a method to store generation data into the framework, I suspect there might be some way to retrieve it too, but so far I don’t know much about it.
- We lose all BRepBuilderAPI_MakeShape specific data, like front, back, etc., which is useful in comparing subshapes between the shapes of a feature before and after modification (thanks @ickby for pointing it out). For this a per-feature reimplementation of BRepBuilderAPI_MakeShape might be necessary to both keep these data, and avoid the huge memory penalty of BRepBuilderAPI_MakeShape.
However, TNaming has a major advantage over BRepBuilderAPI_MakeShape in that it can be created between shapes not necessarily sharing a input-output relationship. We can, thus, store a translated cube as a modification of the original cube. Thus, I now plan to postpone the plan of re-implementing TopoHistory, but create a separate class TopoParaHistory that uses TNaming to relate modifications of the same feature.
Once that is decided, next is how to do the toponaming proper. For that, I had shared an implementation for an idealized model, and I’m sharing it again:
design_notes.txt (4.75 KB)
The horizontal (and diagonal) arrows within the plan would be stored as TopoHistory and the vertical ones will be stored as TopoParaHistory. I planned to complete the TopoNaming solely using the method Part::Feature::execute and it’s redefinitions in the subclasses, as so:
App::DocumentObjectExecReturn *Feature::execute(void)
{
// 1. From para-history of dependencies modify parameters if needed.
// 2. See if something wrong has happened after modification
// 3. Perform the main execute
// 4. Create para-history for this feature
}
Unfortunately this makes an incorrect assumption that execute will only be called once, and that a recompute will call execute of all the shapes when initiated. However, this is not the case. For instance, when editing a sketch, the method has to be called multiple times as we add, remove and modify the various elements of the sketch. Or, it is called multiple times when we modify the parameters of any feature, like the length of a cube. Thus, something like this fails:
>>> # Make Cube (using Button)
>>> oB = App.ActiveDocument.Box.Shape
>>> # Edit length of box from combo-view (say 10 mm -> 5 mm)
>>> nB = App.ActiveDocument.Box.Shape
>>> nB.ParaHistory.modified(oB.Faces[0], oB)
Efforts are underway to figure out how to make a para-history only when the editing between the shape before the editing starts, and that after it finishes. Any inputs as to how this can be achieved will be greatly appreciated.
The developments discussed here can be found on branch tnaming-3 of my fork.