This class implements capping polygons. Capping planes help extend the illusion to the user that he is dealing with actual solids, as opposed to what they really are – boundary representations.
Capping planes are implemented in MVO via the HImCuttingGeometry class. They work by setting an I.M. callback on cutting lines, then collecting those into closed loops from which capping polygons represented as shell faces can be derived. The HImCuttingGeometry class can be used to create polylines, faces or both.
Computation of capping polygons is an operation on solid bodies, so there needs to be some notion of what geometry should be considered as part of the same solid. The normal modes of operation (decided, as described below, with an argument to the CreateCuttingGeometry function) are to consider each shell to be a separate solid or take everything in a segment to collectively represent a solid. In the latter mode, under certain circumstances as described below, entire segment trees can be considered as one.
The main function where all of the magic happens is CreateCuttingGeometry(). This function has four arguments: a) source_key, b) target_key, c) cutting_type, defaulted to HIM_CUTTING_GEOMETRY_TYPE_POLYLINES, and d) body_level, defaulted to HIM_CUTTING_GEOMETRY_SHELL_BODY.
This class is intended to be used to recalculate geometry only when needed, as opposed to once on every update. To that end, we suggest that the user create a dedicated segment for all of the temporary geometry, and keep a flag that is marked "dirty" whenever geometry, or cutting planes move. Note that camera movements don't require recalculation. In that segment, Set_Heuristics("no polygon handedness") as well as Set_Heuristics("concave faces") should be used.
With the HIM_CUTTING_GEOMETRY_SHELL_BODY body_level, a particular user index set to a non-zero value has a special meaning. If the user index defined by H_SOLID_BODY_MAGIC (see htools.h in MVO) is set to something other than zero, everything in and underneath the segment with that index will be considered as part of the same solid body, and merged together. In case you're curious, H_SOLID_BODY_MAGIC is defined as (('b'<<24) | ('o'<<16) | ('d'<<8) | ('y')), which works out to be 0x626f6479. So Set_User_Index( H_SOLID_BODY_MAGIC, 1 ) will cause everything underneath the currently open segment to get merged together as part of the same solid body.
Merging line pieces is asymptotically an O(n^2) operation, and the triangulation can also be quite expensive. Once they are in place, however the cutting geometry is drawn just as fast as if it had been part of the original model until something happens that triggers a recalculation. Segregating solids as much as possible by using the appropriate setting of the body_level argument of CreateCuttingGeometry will help with performance by keeping the "n" in the O(n^2) small.
Proper segregation helps in another way as well: colors. One solid body corresponds to at most one shell face for the capping polygon. The color that will be set on that shell face is the net face color from the segment in which the body was started. Inappropriate use of the H_SOLID_BODY_MAGIC user index at too high a segment can cause color settings from below to be missed, and consequently an inappropriate color applied to the capping polygon.
Under circumstances where only lines are needed, and it is known that the cutting lines will be quickly invalidated, there are two approaches that may perform better. The first is to use HIM_CUTTING_GEOMETRY_TYPE_LINES as the cutting type, which will save the effort of doing any merging. The second possibility is to bypass the HImCuttingGeometry class entirely, with Set_Visibility( "cut lines=on" ). Keep in mind, though, that those approaches are only for when it is known that the cutting lines will be quickly invalidated (since otherwise the upfront computational cost will pay off in future updates).
Numerical problems can create sets of lines that form "loops" with self-intersections. Triangulating such loops is a difficult problem, for which our current approach is not guaranteed to solve perfectly. As a consequence, there will, on occasion, be very thin slivers missing from the capping polygon. To help mitigate such numerical problems, two functions are provided to control the tolerances of a) the smallest feature that is to be considered valid; and b) the allowable distance between endpoints for a "closed" loop to be considered closed.