That is correctDeepSOIC wrote: * Each shape (TopoShape, to be precise) stores a dictionary (map) between subshape and its Toponame Object. The map looks something like this:
"Edge1" <-> <Toponame Object>
"Edge2" <-> <another Toponame Object>
...
They are all listed. It is required that each subshape has a unique Toponame object. The mentioned possibility to name some elements by others (e.g. Edge by the two faces) can be used when setting up the Toponame objects. But after the setting up process every subshape has one.All edges and faces and vertices of the shape are listed. (nor not? there was something about the possibility to figure out an edge off of the other named subelements, such as a combination e.g."Face2", "Face3"))
Yes. This is important, as on reload you are not able to retrieve the information otherwise which would break the naming.These toponame objects and the map can be written to the file (which you wrote is not implemented yet)
In general yes, that is the idea. Most likely it makes sense to port the current subelement handling to also work with those References, functions like "getSubShape(const char* Type)". This would make the change less intrusive.* In SubLink, a hash of the toponame object is remembered, so SubLink will look like this:
>>> App.ActiveDocument.Extrude.DirLink
(<App.ActiveDocument.Box>, ['957620299569'])
And to get the actual edge, I should use this:
dir_edge = App.ActiveDocument.Box.Shape.subshape('957620299569')
And I can look up the hash of an edge like that:
>>> dir_edge.Reference
'957620299569'
Yes, if one only uses a string, one would need to include all base Toponame objects (and their bases etc.) within that string to ensure uniqueness, thats massive. Hence the hashes which include the base hashes.We could have encoded the whole content of the toponame object into a string. However, the strings can get quite long quite quickly, so it may be impractical. That's why hashes are used, as far as I understand
Thats pretty much it, a few remarks:* the toponame object has a few members that store hashes of shapes the subelement came from, as well as a UUID of an operation that was performed.
toponame_object.Type = [either NEW, GENERATED, or MERGED]
toponame_object.Base = ['28389275', '00198646'] #(list of hashes of subshapes this subshape was created from)
toponame_object.Name = <string> # (optional - a human-readable identifier of the shape, if toponame_object.Type == NEW)
toponame_object.Operation = <what? another object?>
toponame_object.OperationUUID = 187364901973 # this should be somehow tied to the feature that performs the operation, this is an unclear bit so far
toponame_object.Counter = <int> # if shape happens to get a few subelements with exactly the same toponame objects, this property is bumped up to make correspondence subshape<->toponame_object unique within this shape.
- Currently the Reference class, what you call toponame_object, is not exposed to python. I thought that eachgeometry algorithm in TopoShape should be ported to setup those, hence no need to handle them in python.
- Base - list of hashes. This is not a list of hashes, but of full identifiers. The reason for that is the querying. If you only have base hashes, you can't access any information of those as you don't know the shape they are available in. You need the full base identifier to be able to answer queries like "isConstructedFrom" of a base that is deep in the identifier tree. Also "isMergedFrom" could need more than one layer of the history. In current implementation that list contains copies. That is not very efficient in terms of memory, but was easy to start with. Later on one could implement a more elaborate sharing mechanism with pointer or something.
- The Operation. The first idea when building a creation history is to use the operation type used to create a subshape (e.g. extrude, revolve, sweep...). This gives you two advantages, for one a strong criteria to make subshapes unique (e.g. e vertex revolved and than the edge extruded: two edges will only differ by operation), and on the other side gives you some expressivness, something the user can understand and work with.
- OperationUUID. It turned out that the Operation type property is not enough from the uniqueness point of view, as was shown with the "extrude extrude" example. Hence an Operation also gets a UUID, which is a random value for each operation. That means the first extrude would have a different UUID than the second, where Operation is the same (e.g. "Extrude"). This makes it possible to uniquely name different modeling steps. Arguably this makes "Operation" property obsolete, however I keept it for now for its expressiveness.
- OperationUUID and features. As the UUID is randomly created when not otherwise specified recompute is a problem. It would create a new UUID and hence the identifiers would not be the same, even thougth they should be. Hence the requirement to store an UUID within in a Part::Feature and assign that always same UUID to the identifiers created in that document object.
If a subshape did not change by the operation like the shown vertex its identifier would not change at all. It is still the same vertex. On the technical side this is done by copying over the identifier from the former shape. I don't fully grasp your question, so you may elaborate a bit more about what is unclear here.1. on diagrams, you show that a vertex persistently gets the same exact hash (and it is a small number) as more and more extrusions are applied to it. How is that possible? (most likely there's something wrong with my understanding) ... Is it just taking the history object of the original Vertex in its full glory, which consequently has the same hash? If so, the hashes pointed by that history object may become unresolvable...
Yes, and most likely also many others. I intended to add more there on the go, whenever a new algorithm porting would need it.2. I think the Type enum is missing a "SPLIT" item.
The general idea of count was that there may be situations where all other properties are not enough to make unique identifiers within a certain shape. Imagine a edge that get splitted. Afte the split you have two edes with the exact same identifer, same base, same operation etc. This would not be unique. Hence counter, one edge would become counter 1 and the other counter 2.I think I figured out, what "Count" is supposed to do.
Clone is a special case. Uniqueness of ids is only required within a shape, not freecad wide. Personally I think a clone should have the excact same identifiers than the original one. It is the same shape after all. And it would make sense to find a certain vertex via references within the original and the clone.