GSoC 2017 Dev Log: jnxd

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Posts: 162
Joined: Mon Mar 30, 2015 2:30 pm

Re: GSoC 2017 Dev Log: jnxd

Postby jnxd » Tue Aug 29, 2017 2:09 pm

chrisb wrote:
Tue Aug 29, 2017 1:12 pm
Do you have the feeling, that this can be solved after all? I mean a sound, always applicable technique. I can only think of some heuristics to solve this problem, because for us humans it is most of the time easy to see which edges, vertices and faces correspond if we have a state before and after a change, but this is very hard to do by a machine.
Example: if I take something like a simple cube and cut it in two pieces of different size; which face should get the same number as before? Which edges are the same?
There will eventually have to be heuristics involved in this project. However, if we want to limit to just elements that can be identified solely using faces and their intersections, a sound technique is available. This will force us to use wires instead of edges in many cases. Of course, there is a problem of what to do when the faces themselves are split/merged.
Posts: 557
Joined: Tue May 19, 2015 1:11 am

Re: GSoC 2017 Dev Log: jnxd

Postby ezzieyguywuf » Tue Aug 29, 2017 2:11 pm

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.

In closing

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.
Posts: 557
Joined: Tue May 19, 2015 1:11 am

Re: GSoC 2017 Dev Log: jnxd

Postby ezzieyguywuf » Tue Aug 29, 2017 2:13 pm

chrisb wrote:
Tue Aug 29, 2017 1:12 pm
Example: if I take something like a simple cube and cut it in two pieces of different size; which face should get the same number as before? Which edges are the same?
In my opinion, in this situation, no face will get the same number as before. However, I do think it makes sense to allow for a sort of Topological Inheritance.

In other words, in your example, if "Face001" is split into two, then the resulting solid may have "Face001a" and "Face001b", both of which will internally store data that flags them as "children" of the original "Face001". In this way, per my previous post, the client code can make intelligent decision about what to do in these circumstances.