The purpose of these examples is to show you how to go about programming
your own functions using svLis. Note
in particular that the first example need not be a friend of any of the
classes it uses--the accessing functions built into the classes to return
such things as the two child operands of a set-theoretic operator are sufficiently
rich to allow any possible function to be programmed. The only private
data in the classes are for housekeeping--things such as reference counts
for items pointed to and so on--and are, in a sense, not part of the svLis
geometric modeller at all, but merely necessary adjuncts to allow efficient
storage management, reliable and compact input and output, and so on.
It is of course possible to perform a membership test to classify a point against a model without dividing it. First a check would be done that the point was in the model's box. If not, then a conventional code for air would be returned as the result. If the point were in the box, it would be tested against each set in the model's list of sets. If the point was found to be in any set, a code indicating solid would be returned (the list is regarded as being unioned for the purpose of membership testing). Failing that, if the point was found to be on the surface of a set, a code for surface would be returned; otherwise the result would be a code for air.
However, for complicated sets this would be a very inefficient process, especially if a large number of points were to be tested. It is much better to divide the model first (for example using the naïve decision procedure dumb_decision(...); see Page ). Then, svLis performs a recursive traversal of the tree of model boxes until the leaf box containing the point to be tested is found; and that point is tested against the simple pruned list of sets in that leaf model. This is how the membership test function works:
This traverses the model's tree of boxes, comparing the coordinates of the point with the coordinates of the planes that divide any box into its two smaller children and selecting the appropriate child. When a leaf is reached, the membership test is done for all the sets in the list of sets at that leaf. The array of primitives known_surface[ ] allows the user to provide the function with a list of primitives for which the point is known to be on the surface (which would happen, for instance, if the point was at the intersection of the surfaces of three primitives coming together in a corner). This known-surface array makes the membership test more efficient, as it removes the need for the system to categorize the point against the primitives which (in the example) generated it. If known-surface information is not available, just send the function a pointer to an undefined primitive as its third argument, and this will be ignored.// Membership test a point against a model. mem_test member(const sv_model& m, const sv_point& p, sv_primitive known_surface[]) { mem_test result = SV_AIR; mem_test temp = SV_AIR; sv_set_list sl; // Is the point in the model's box? if(m.box().member(p) == SV_AIR) return(SV_AIR); // If m is a leaf, check against each set in the leaf's // list. Otherwise walk down the model tree. switch (m.kind()) { case LEAF_M: sl = m.set_list(); while(sl.exists()) { temp = sl.set().member(p, known_surface)); if (temp == SV_SOLID) return(SV_SOLID); if (temp == SV_SURFACE) result = SV_SURFACE; sl = sl.next(); } return(result);case X_DIV: if (p.x < m.coord()) return(m.child_1().member(p,known_surface)); else return(m.child_2().member(p,known_surface));case Y_DIV: if (p.y < m.coord()) return(m.child_1().member(p,known_surface)); else return(m.child_2().member(p,known_surface));case Z_DIV: if (p.z < m.coord()) return(m.child_1().member(p,known_surface)); else return(m.child_2().member(p,known_surface));default: svlis_error("member(sv_model, ...)", "dud model kind", SV_CORRUPT); } // Should never get here. svlis_error("member(sv_model, ...)", "error in model; returning SV_AIR",SV_CORRUPT); return(SV_AIR); }
There are a couple of errors at the end of the function which should
only be printed if the data structures have been corrupted somehow.
The function first checks to see if it has been given the universal or the empty set, in which case the answer--following an appropriate convention--is immediately returned. If the set is a leaf containing a single primitive the range for that is calculated and returned. If the set is a union or an intersection, the function calls itself recursively for the two child operands, then combines the results appropriately. Finally, it makes sure that any attributes are inherited properly by the two sets that are returned by means of the pointer arguments.// Range for a box (and winning leaf sets). sv_interval sv_set::range (const sv_box& b, sv_set* w_lo, sv_set* w_hi) { sv_interval result_2; sv_interval result; sv_set w_2_lo, w_2_hi; switch (contents()) { case SV_EVERYTHING: w_lo = this; w_hi = this; return(sv_interval(-2.0,-1.0)); // By convention case SV_NOTHING: w_lo = this; w_hi = this; return(sv_interval(1.0,2.0)); // By convention // Leaf set - return corresponding primitive's range // for box b. case 1: w_lo = this; w_hi = this; return(primitive().range(b)); // Compound set - recursively call range for the // children. default: result = child_1().range(b, w_lo, w_hi); result_2 = child_2().range(b ,&w_2_lo, &w_2_hi); if (operator() == SV_UNION) // U == minimum { if (result_2.lo < result.lo) { *w_lo = w_2_lo; result.lo = result_2.lo; } if (result_2.hi < result.hi) { *w_hi = w_2_hi; result.hi = result_2.hi; } } else { // SV_INTERSECTION == maximum if (result_2.lo > result.lo) { *w_lo = w_2_lo; result.lo = result_2.lo; } if (result_2.hi > result.hi) { *w_hi = w_2_hi; result.hi = result_2.hi; } } // Keep track of the attributes. if ( this->has_attribute() && ( !(w_lo->has_attribute()) ) ) *w_lo = w_lo->attribute(this->attribute()); if ( this->has_attribute() && ( !(w_hi->has_attribute()) ) ) *w_hi = w_hi->attribute(this->attribute());return(result); } }
As mentioned in the Foreword, svLis was written both as a research and as a commercial geometric modeller. A number of current research projects are using it, and the results of those projects will be incorporated into svLis in the future. Additional facilities, not linked to a particular project, are being developed as well. This section gives a list of some of the current plans; I should say that directions--particularly on the research side--may change, so some objectives may be reduced in priority and some new aims may be introduced.