jnxd wrote: ↑
Tue Aug 29, 2017 12:51 pm
The project is definitely far from over. I had initially hoped to at least reach a point where a classical problem of filleting an edge/edges of a box with a slot can be solved, but technical and other difficulties prevented that from happening. This goal still stays a stepping stone towards complete topological naming. Some of the major issues towards this goal are:
- Where to create the various TopoHistory/TopoParaHistory objects needed to be stored? Initially the idea was to do so in Part::Feature::execute, but it turns out that that method is called multiple times on a single shape before it is called on subsequent shapes, making it harder to find a relation between the old shape and the new.
- TopoParahistory relies on the TNaming framework, which, unfortunately, only seems to be working well for modifications, but not for generations or deletions.
- Apart from this there are some more fundamental challenges. One example is that we are so far using just the modification of faces in a solid to track the modification of all edges/vertices. But what happens when there are multiple edges in common between the same face(s)?
To summarize the project has helped me with understanding the problems faced during topological naming, and also gave me an experience with collaboration in a FOSS software. Despite it's failure, I am optimistic that I would be able to develop this project further.
@jnxd, I know you've tried reaching out to me a few times regarding the work I did on this last year and that I have not been very helpful. I would like to apologize for that. I do have a few comments on your list that I've quoted above.
Where to create history objects?
I think the proper place to store
this data is as a private member of Part::TopoShape. I also believe that the proper place to create
this data is within the various Part::Feature::execute methods.
To your point, this method tends to get called multiple times. On the one hand, a part of me feels that the larger FreeCAD project itself can do a better job managing when/if this execute method must be called. On the other hand, perhaps there are good, sound design reasons why Execute is called as often as it is.
Either way, as often as Execute is called, the history object must be created/updated. The reason for this is because (as far as I can tell) each Part::Feature::execute physically changes the TopoDS_Shape that is stored it TopoShape. Any time that TopoDS_Shape changes, the history object needs to be updated. The history object itself should have some mechanism whereby it can check whether or not anything in the tracked shape has actually changed, thereby minimizing (or eliminating) any redundant data.
TNaming does not work well for Generations and Deletions
I'm not sure if I agree with this. If you take a look at the documentation for TNaming_Builder
, you'll notice that it has "Generated", "Deleted" and "Modify" methods. These are each intended to create the appropriate nodes in occ's "OCAF" data framework. Admittedly, I'm not a big fan of OCAF, as I find it cumbersome and annoying, but I have been able to successfully test the "Generated" and "Modify" methods of this TNaming_Builder class and they both seem to work fine when used appropriately.
What happens when there are multiple Edges in common between the same Face?
I assume you mean what happens when an Edge which is shared by two Faces all of a sudden becomes a "split Edge". In other words, if "Edge001" is described as "The edge between Face001 and Face002", what happens when a slot is added such that there are now two Edges between Face001 and Face002.
In my opinion, this is not a problem for the "Topological Namer" to deal with - this must be dealt with in the client code. Rather, the Topological Namer must simply provide the pertinent data. For example, in my python prototype
you'll notice that the "getEdgeByName" method returns a list of Edges rather than a single Edge. In my opinion, this is sufficient to deal with the question at hand - it is now incumbent upon the client code to check whether an expected number of Edges is returned, and if not to choose what to do.
Let me provide a concrete example. Say we have simple Cube and a single Edge is filleted. Next, this filleted Edge is split in two. The client code now goes to rebuild the filleted Cube, and in doing so uses the "history object" to perform some equivalent of:
Code: Select all
edgesToFillet = historyObject.getEdgeByName(filletedEdgeName);
The client code may "know" that originally it filleted a single edge (maybe it stored this data somewhere). It also now knows that there are two Edges where before there was one. In my opinion, it would be perfectly logical for the client code to now fillet both Edges.
What if this was the other way around? Originally, there are two edges between "Face001" and "Face002" and only one of them is filleted. Now, a change is made and suddenly there is only one Edge there. What will happen?
When the "getEdgeByName" method is called, a single Edge will be returned when before there were two. In my opinion, the client code should now prompt the user as to whether or not this Edge should be filleted. Again, though ,this is not a problem for the "history object" to deal with.
I do not intend for any of my commentary to be definitive or inflammatory. I am merely trying to maintain an open discussion regarding my thoughts, views, and understanding of these topological naming issues.