Posted to tcl by hypnotoad at Fri Jan 22 16:28:19 GMT 2016view raw
-  
 - /*
 - ** This file implements a TCL object that keeps track of the walls and
 - ** bulkheads on a single deck of a ship.
 - **
 - ** This widget assumes a right-handed coordinate system if zoom is positive
 - ** and a left-handed coordinate system is zoom is negative.  The Tk canvas
 - ** widget uses a left-handed coordinate system all the time.  The READI
 - ** database uses a right-handed coordinate system all the time.  This module
 - ** can be used to translate by setting zoom to +1.0 for database I/O and
 - ** to -$g(zoom) for canvas I/O.
 - **
 - ** This module uses a purely 2-D model.  It can only handle a single
 - ** deck at a time.  If a multi-deck model needs to be displayed then
 - ** that multi-deck model should first be flattened into a stack of
 - ** individual decks in the same plane using the separate "slicer" object.
 - **
 - ** This file implements a single new constructor tcl command named "wallset".
 - ** The wallset command creates a new wallset object.  Methods on this
 - ** wallset object are used to manage the object.
 - **
 - ** The details of the various methods and what they do are provided in
 - ** header comments above the implementation of each method.
 - */
 -  
 - #include "odielibInt.h"
 - #include <tclOO.h>
 - #include <stdarg.h>
 - #include <stdlib.h>
 - #include <assert.h>
 - #include <string.h>
 - #include <math.h>
 -  
 - #ifndef M_PI
 - # define M_PI 3.1415926535898
 - #endif
 -  
 - /*
 - ** Remove all of the ComptBox entries from the wallset.
 - */
 - static void clearComptBoxCache(Wallset *pWS){
 -   ComptBox *p = pWS->pComptBox;
 -   while( p ){
 -     ComptBox *pNext = p->pNext;
 -     Odie_Free((char *)p);
 -     p = pNext;
 -   }
 -   pWS->pComptBox = 0;
 - }
 -  
 - /*
 - ** This routine is invoked when the TCL command that implements a
 - ** wallset is deleted.  Free all memory associated with that
 - ** wallset.
 - */
 - static void destroyWallset(void *pArg){
 -   Wallset *p = (Wallset*)pArg;
 -   Link *pLink = p->pAll;
 -   clearComptBoxCache(p);
 -   while( pLink ){
 -     Segment *pSeg = pLink->pLinkNode;
 -     pLink = pSeg->pAll.pNext;
 -     Odie_Free((char *) pSeg );
 -   }
 -   Odie_Free((char *) p );
 - }
 -  
 - /*
 - ** Clear the Segment.ignore flag on all segments within a wallset.
 - */
 - static void ignoreNone(Wallset *p){
 - #if 0  
 -   Link *pLink;
 -   for(pLink=p->pAll; pLink; pLink=pLink->pNext){
 -     pLink->pSeg->ignore = 0;
 -   }
 - #endif
 - }
 -  
 - /*
 - ** Return a pointer to the segment with the given ID.  Return NULL
 - ** if there is no such segment.
 - */
 - static Segment *findSegment(Wallset *p, int id){
 -   int h;
 -   Link *pLink;
 -  
 -   h = hashInt(id);
 -   for(pLink = p->hashId[h]; pLink; pLink=pLink->pNext){
 -     Segment *pSeg=pLink->pLinkNode;
 -     if( pSeg->id==id ) return pSeg;
 -   }
 -   return 0;
 - }
 -  
 - /*
 - ** Scan all segments looking for the vertex or vertices that are nearest
 - ** to x,y.  Return a pointer to a Segment.set that is the list of matching
 - ** segments.  Also write the nearest point into *pX,*pY.
 - **
 - ** The returned list uses the Segment.set link.
 - */
 - static Link *nearestVertex(
 -   Wallset *p,               /* The wallset to be scanned */
 -   double x, double y,       /* Search for points near to this point */
 -   double *pX, double *pY    /* Write nearest vertex here */
 - ){
 -   double nx, ny;
 -   double min = -1.0;
 -   Link *pList = 0;
 -   Link *pI;
 -  
 -   x = roundCoord(x);
 -   y = roundCoord(y);
 -   for(pI=p->pAll; pI; pI=pI->pNext){
 -     double dx, dy, dist;
 -     Segment *pSeg = pI->pLinkNode;
 -     dx = x - pSeg->from[X_IDX];
 -     dy = y - pSeg->from[Y_IDX];
 -     dist = dx*dx + dy*dy;
 -     if( min<0.0 || dist<=min ){
 -       if( min<0.0 || nx!=pSeg->from[X_IDX] || ny!=pSeg->from[Y_IDX] ){
 -         pList = 0;
 -         nx = pSeg->from[X_IDX];
 -         ny = pSeg->from[Y_IDX];
 -         min = dist;
 -       }
 -       LinkInit(pSeg->pSet, pSeg);
 -       LinkInsert(&pList, &pSeg->pSet);
 -     }
 -     dx = x - pSeg->to[X_IDX];
 -     dy = y - pSeg->to[Y_IDX];
 -     dist = dx*dx + dy*dy;
 -     if( dist<=min ){
 -      if( nx!=pSeg->to[X_IDX] || ny!=pSeg->to[Y_IDX] ){
 -         pList = 0;
 -         nx = pSeg->to[X_IDX];
 -         ny = pSeg->to[Y_IDX];
 -         min = dist;
 -       }
 -       LinkInit(pSeg->pSet, pSeg);
 -       LinkInsert(&pList, &pSeg->pSet);
 -     }
 -   }
 -   *pX = nx;
 -   *pY = ny;
 -   return pList;
 - }
 -  
 - /*
 - ** Scan all segments looking for the point on a segment that is nearest
 - ** to x,y.  Return a pointer to a Segment.set that is the list of matching
 - ** segments.  This set might contain multiple members if the nearest point
 - ** is actually a vertex shared by two or more segments.  Write the nearest
 - ** point into *pX, *pY.
 - **
 - ** /// Ignore any segment that has its Segment.ignore flag set. -- removed
 - **
 - ** The returned list uses the Segment.set list.
 - */
 - static Link *nearestPoint(
 -   Wallset *p,               /* The wallset to be scanned */
 -   double x, double y,       /* Search for points near to this point */
 -   double *pX, double *pY    /* Write nearest vertex here */
 - ){
 -   double nx, ny;
 -   double min = -1.0;
 -   Link *pList = 0;
 -   Link *pI;
 -  
 -   x = roundCoord(x);
 -   y = roundCoord(y);
 -   for(pI=p->pAll; pI; pI=pI->pNext){
 -     double dx, dy, dist;
 -     Segment *pSeg;
 -     double acx, acy;   /* Vector from x0,y0 to x,y */
 -     double abx, aby;   /* Vector from x0,y0 to x1,y1 */
 -     double rx, ry;     /* Nearest point on x0,y0->to[X_IDX],y1 to x,y */
 -     double r;
 -  
 -     pSeg = pI->pLinkNode;
 -     /* if( pSeg->ignore ) continue; */
 -     acx = x - pSeg->from[X_IDX];
 -     acy = y - pSeg->from[Y_IDX];
 -     abx = pSeg->to[X_IDX] - pSeg->from[X_IDX];
 -     aby = pSeg->to[Y_IDX] - pSeg->from[Y_IDX];
 -     r = (acx*abx + acy*aby)/(abx*abx + aby*aby);
 -     if( r<=0 ){
 -       rx = pSeg->from[X_IDX];
 -       ry = pSeg->from[Y_IDX];
 -     }else if( r>=1 ){
 -       rx = pSeg->to[X_IDX];
 -       ry = pSeg->to[Y_IDX];
 -     }else{
 -       rx = pSeg->from[X_IDX] + abx*r;
 -       ry = pSeg->from[Y_IDX] + aby*r;
 -     }
 -     rx = roundCoord(rx);
 -     ry = roundCoord(ry);
 -     dx = x - rx;
 -     dy = y - ry;
 -     dist = dx*dx + dy*dy;
 -     if( min<0.0 || dist<=min ){
 -       if( min<0.0 || nx!=rx || ny!=ry ){
 -         pList = 0;
 -         nx = rx;
 -         ny = ry;
 -         min = dist;
 -       }
 -       LinkInit(pSeg->pSet, pSeg);
 -       LinkInsert(&pList, &pSeg->pSet);
 -     }
 -   }
 -   *pX = nx;
 -   *pY = ny;
 -   return pList;
 - }
 -  
 - /*
 - ** Return TRUE if the value x is in between x1 and x2.
 - */
 - static int between(double x, double x1, double x2){
 -   if( x1<x2 ){
 -     return x>=x1 && x<=x2;
 -   }else{
 -     return x>=x2 && x<=x1;
 -   }
 - }
 -  
 - /*
 - ** Return TRUE if the given segment is on the given list
 - */
 - static int segmentOnList(Segment *pSeg, Link *pList){
 -   while( pList ){
 -     if( pList->pLinkNode==pSeg ) return 1;
 -     pList = pList->pNext;
 -   }
 -   return 0;
 - }
 -  
 - /*
 - ** Return a list of all segments which have an end at the given vertex.
 - ** The returned list uses Segment.set
 - */
 - static Link *segmentsAtVertex(Wallset *p, double x, double y){
 -   Link *pList = 0;
 -   Link *pI;
 -   int h;
 -  
 -   x = roundCoord(x);
 -   y = roundCoord(y);
 -   h = hashCoord(x, y);
 -   for(pI=p->hashFrom[h]; pI; pI=pI->pNext){
 -     Segment *pSeg = pI->pLinkNode;
 -     /* if( pSeg->ignore ) continue; */
 -     if( floatCompare(x, pSeg->from[X_IDX])==0 && floatCompare(y, pSeg->from[Y_IDX])==0 ){
 -       assert( !segmentOnList(pSeg, pList) );
 -       LinkInit(pSeg->pSet, pSeg);
 -       LinkInsert(&pList, &pSeg->pSet);
 -     }
 -   }
 -   for(pI=p->hashTo[h]; pI; pI=pI->pNext){
 -     Segment *pSeg = pI->pLinkNode;
 -     /* if( pSeg->ignore ) continue; */
 -     if( floatCompare(x, pSeg->to[X_IDX])==0 && floatCompare(y, pSeg->to[Y_IDX])==0 ){
 -       assert( !segmentOnList(pSeg, pList) );
 -       LinkInit(pSeg->pSet, pSeg);
 -       LinkInsert(&pList, &pSeg->pSet);
 -     }
 -   }
 -   return pList;
 - }
 -  
 - /*
 - ** The point xV,yV is a vertex in the wallset.  This routine locates
 - ** a segment connected to that vertex which is the first segment in
 - ** a clockwise direction from xR,yR->xV,yV.  A pointer to the segment
 - ** is written into *ppSeg.  If the output segment moves backwards
 - ** (in other words if x1,y1 of the segment is connected at xV,yV)
 - ** then *pfBack is true.
 - **
 - ** If a suitable segment is found, 0 is returned.  Non-zero is returned
 - ** if no suitable segment could be found.
 - **
 - ** This routine uses the Segment.set list internally.
 - */
 - static int nextCwSegment(
 -   Wallset *p,              /* The wallset */
 -   double xR, double yR,    /* Remote end of input segment */
 -   double xV, double yV,    /* Vertex (near end of input segment) */
 -   Segment **ppSeg,         /* OUT: First segment clockwise from xR,yR->xV,yV */
 -   int *pfBack              /* OUT: True if output segment goes backwards */
 - ){
 -   Link *pList, *pI;
 -   double rRef, rBest;
 -   int i, nSeg, iBest;
 -   Segment *pSeg;
 -   struct {
 -     Segment *pSeg;
 -     int isBack;
 -     double rAngle;
 -   } *aSeg, aSegStatic[20];
 -  
 -   /* Find all segments at xV,yV */
 -   pList = segmentsAtVertex(p, xV, yV);
 -   for(pI=pList, nSeg=0; pI; nSeg++, pI=pI->pNext){}
 -   if( nSeg==0 ) return 1;
 -   if( nSeg<=sizeof(aSegStatic)/sizeof(aSegStatic[0]) ){
 -     aSeg = aSegStatic;
 -   }else{
 -     aSeg = (void *)Odie_Alloc( nSeg*sizeof(*aSeg) );
 -   }
 -   for(pI=pList, i=0; pI; i++, pI=pI->pNext){ 
 -     aSeg[i].pSeg = pSeg = pI->pLinkNode;
 -     aSeg[i].isBack = floatCompare(xV, pSeg->to[X_IDX])==0 
 -                           && floatCompare(yV, pSeg->to[Y_IDX])==0;
 -   }
 -  
 -   /* Find the reference angle */
 -   rRef = atan2(yR-yV, xR-xV)*180.0/M_PI;
 -  
 -   /* Find angles on all segments */
 -   for(i=0; i<nSeg; i++){
 -     pSeg = aSeg[i].pSeg;
 -     if( aSeg[i].isBack ){
 -       aSeg[i].rAngle = atan2(pSeg->from[Y_IDX]-pSeg->to[Y_IDX], pSeg->from[X_IDX]-pSeg->to[X_IDX])*180.0/M_PI;
 -     }else{
 -       aSeg[i].rAngle = atan2(pSeg->to[Y_IDX]-pSeg->from[Y_IDX], pSeg->to[X_IDX]-pSeg->from[X_IDX])*180.0/M_PI;
 -     }
 -   }
 -  
 -   /* Subtract 360 to any segment angle that is less than the reference angle */
 -   for(i=0; i<nSeg; i++){
 -     if( aSeg[i].rAngle<rRef ) aSeg[i].rAngle += 360;
 -   }
 -  
 -   /* Choose the segment with the largest angle */
 -   rBest = aSeg[0].rAngle;
 -   iBest = 0;
 -   for(i=1; i<nSeg; i++){
 -     if( aSeg[i].rAngle>rBest ){
 -       iBest = i;
 -       rBest = aSeg[i].rAngle;
 -     }
 -   }
 -   *ppSeg = aSeg[iBest].pSeg;
 -   *pfBack = aSeg[iBest].isBack;
 -   if( aSeg!=aSegStatic ){
 -     Odie_Free((char *) aSeg );
 -   }
 -  
 -   return 0;
 - }
 -  
 - /*
 - ** Consider a line beginning at x0,y0 then going from x1,y1 to x2,y2.
 - ** x1,y1 is an elbow in the line.  This routine returns -1 if the
 - ** elbow bends to the right, and +1 if it bends to the left.  zero is
 - ** returned if the elbow does not bend at all.
 - */
 - static int bendDirection(
 -   double x0, double y0,
 -   double x1, double y1,
 -   double x2, double y2
 - ){
 -   /* Algorithm:  Rotate x0,y0->to[X_IDX],y1 90 degrees counter-clockwise.  Take
 -   ** the dot product with x1,y1->x2,y2.  The dot produce will be the product
 -   ** of two (non-negative) magnitudes and the cosine of the angle.  So if
 -   ** the dot product is positive, the bend is to the left, or to the right if
 -   ** the dot product is negative.
 -   */
 -   double r = (y0-y1)*(x2-x1) + (x1-x0)*(y2-y1);
 -   return r<0.0 ? +1 : (r>0.0 ? -1 : 0);
 - }
 -  
 - /*
 - ** Given an interior point xI,yI, this routine finds a segment on the
 - ** boundary that contains the interior point.  That segment is returned
 - ** in *ppSeg.  *pfLeft is set to true if the interior point is to the left
 - ** of the segment and false if it is to the right.
 - **
 - ** Zero is returned on success.  Non-zero is returned if no suitable
 - ** boundary could be located.  Non-zero might be returned, for example,
 - ** if xI,yI is positioned directly on top of a wall or if there are no
 - ** walls in the wallset.
 - **
 - ** // Any segment marked with Segment.ignore is ignored for purposes of
 - ** // this routine.  -- removed
 - **
 - ** This routine uses the Segment.set list internally.
 - */
 - static int firstBoundarySegment(
 -   Wallset *p,              /* The wallset */
 -   double xI, double yI,    /* An interior point */
 -   Segment **ppSeg,         /* OUT: A segment on the boundary containing xI,yI */
 -   int *pfLeft              /* OUT: True if xI,yI is to the left side *ppSeg */
 - ){
 -   Link *pList;
 -   double xN, yN;
 -  
 -   /* Find nearest point, xN,yN */
 -   pList = nearestPoint(p, xI, yI, &xN, &yN);
 -   if( pList==0 ) return 1;
 -   if( pList->pNext ){
 -     /* xN,yN is a vertex...
 -     ** Locate the first segment clockwise from xI,yI->xN,yN and return
 -     */
 -     return nextCwSegment(p, xI, yI, xN, yN, ppSeg, pfLeft);
 -   }else{
 -     /* xN,yN is a point on single line segment...
 -     */
 -     Segment *pSeg;
 -     pSeg = *ppSeg = pList->pLinkNode;
 -     *pfLeft = bendDirection(pSeg->from[X_IDX], pSeg->from[Y_IDX], xN, yN, xI, yI)>0;
 -   }
 -   return 0;
 - }
 -  
 - /*
 - ** Fill the given Boundary array with a list of segments (with
 - ** Segment.ignore set to false) that form a closed circuit.  The
 - ** first entry in aBound[] has already been filled in by the
 - ** calling function and is used to seed the search.
 - **
 - ** At most nBound slots in aBound[] will be used.  The return value
 - ** is the number of slots in aBound[] that would have been used if those
 - ** slots had been available.  A return of 0 indicates that no boundary
 - ** is available.
 - **
 - ** If the checkIsPrimary flag is true and the aBound[0] entry is not
 - ** the primary segment for the compartment, then the aBound[] is not
 - ** completely filled in and the routine returns 0;
 - */
 - static int completeBoundary(
 -   Wallset *p,             /* The wallset */
 -   int checkIsPrimary,     /* Abort if aBound[0] is not the primary segment */
 -   int nBound,             /* Number of slots available in aBound[] */
 -   Boundary *aBound        /* IN-OUT: Write results into aBound[1...] */
 - ){
 -   int cnt = 1;
 -   Segment *pSeg, *pS;
 -   int isLeft;
 -   int isBack;
 -   double xR, yR, xV, yV;
 -  
 -   pS = pSeg = aBound[0].pSeg;
 -   isLeft = aBound[0].backwards;
 -   if( !isLeft ){
 -     xR = pSeg->from[X_IDX];
 -     yR = pSeg->from[Y_IDX];
 -     xV = pSeg->to[X_IDX];
 -     yV = pSeg->to[Y_IDX];
 -   }else{
 -     xV = pSeg->from[X_IDX];
 -     yV = pSeg->from[Y_IDX];
 -     xR = pSeg->to[X_IDX];
 -     yR = pSeg->to[Y_IDX];
 -   }
 -   while( nextCwSegment(p,xR,yR,xV,yV,&pS,&isBack)==0 &&
 -               (isBack!=isLeft || pS!=pSeg) ){
 -     if( checkIsPrimary ){
 -       if( pS->id<pSeg->id ) return 0;
 -       if( pS->id==pSeg->id && !isLeft ) return 0;
 -     }
 -     if( isBack ){
 -       xV = pS->from[X_IDX];
 -       yV = pS->from[Y_IDX];
 -       xR = pS->to[X_IDX];
 -       yR = pS->to[Y_IDX];
 -     }else{
 -       xR = pS->from[X_IDX];
 -       yR = pS->from[Y_IDX];
 -       xV = pS->to[X_IDX];
 -       yV = pS->to[Y_IDX];
 -     }
 -     if( nBound>cnt ){ 
 -       aBound[cnt].pSeg = pS;
 -       aBound[cnt].backwards = isBack;
 -     }
 -     cnt++;
 -     if( cnt>1000 /* 00 */ ) return -cnt;   /* Avoid an infinite loop */
 -   }
 -   return cnt;
 - }
 -  
 - /*
 - ** Compute the "spin" on a boundary.  A positive value means the
 - ** circulation is to counter-clockwise and a negative value means the 
 - ** circulation is clockwise.  For boundaries, a positive
 - ** value means the region is internal and a negative value means
 - ** the region is external.
 - */
 - static double spin(Boundary *aBound, int nBound){
 -   double sum = 0;
 -   int i;
 -   for(i=0; i<nBound; i++){
 -     double x0, y0, x1, y1;
 -     double dx, dy;
 -     Segment *pSeg = aBound->pSeg;
 -     if( aBound->backwards ){
 -       x0 = pSeg->to[X_IDX];
 -       y0 = pSeg->to[Y_IDX];
 -       x1 = pSeg->from[X_IDX];
 -       y1 = pSeg->from[Y_IDX];
 -     }else{
 -       x0 = pSeg->from[X_IDX];
 -       y0 = pSeg->from[Y_IDX];
 -       x1 = pSeg->to[X_IDX];
 -       y1 = pSeg->to[Y_IDX];
 -     }
 -     aBound++;
 -     dx = x1-x0;
 -     dy = y1-y0;
 -     sum += x0*dy - y0*dx;
 -   }
 -   return sum;
 - }
 -  
 - /*
 - ** The input is two linked lists of ComptBox structures where each
 - ** list is sorted by increasing area.  Combine these two lists into
 - ** a single sorted linked list.
 - */
 - static ComptBox *mergeComptBox(ComptBox *p1, ComptBox *p2){
 -   ComptBox head;
 -   ComptBox *pTail = &head;
 -   ComptBox *p;
 -   while( p1 && p2 ){
 -     if( p1->area<=p2->area ){
 -       p = p1->pNext;
 -       pTail->pNext = p1;
 -       pTail = p1;
 -       p1 = p;
 -     }else{
 -       p = p2->pNext;
 -       pTail->pNext = p2;
 -       pTail = p2;
 -       p2 = p;
 -     }
 -   }
 -   if( p1 ){
 -     pTail->pNext = p1;
 -   }else{
 -     pTail->pNext = p2;
 -   }
 -   return head.pNext;
 - }
 -  
 - /*
 - ** Construct the ComptBox cache.  For each compartment (where a compartment
 - ** is a closed circuit of Segments) make an entry on the Wallset.pComptBox
 - ** list.
 - **
 - ** If the ComptBox cache already exists, this routine is a no-op.
 - */
 - static void buildComptBoxCache(Wallset *p){
 -   Link *pI;
 -   int i;
 -   ComptBox *aSort[30];
 -  
 -   /* Return immediately if the cache already exists */
 -   if( p->pComptBox ) return;
 -  
 -   /* Compute a linked list of all compartment boxes */
 -   for(pI=p->pAll; pI; pI=pI->pNext){
 -     int i, j, n;
 -     Boundary aBound[1000];
 -  
 -     aBound[0].pSeg = pI->pLinkNode;
 -     for(j=0; j<2; j++){
 -       aBound[0].backwards = j;
 -       n = completeBoundary(p, 1, sizeof(aBound)/sizeof(aBound[0]), aBound);
 -       if( n>0 && spin(aBound,n)>0.0 ){
 -         double dx, dy;
 -         Segment *pSeg = pI->pLinkNode;
 -         ComptBox *pNew = (ComptBox *)Odie_Alloc( sizeof(*pNew) );
 -         pNew->pNext = p->pComptBox;
 -         pNew->bbox.l = pNew->bbox.r = pSeg->from[X_IDX];
 -         pNew->bbox.t = pNew->bbox.b = pSeg->from[Y_IDX];
 -         pNew->prim = aBound[0];
 -         for(i=1; i<n; i++){
 -           Segment *pSeg = aBound[i].pSeg;
 -           if( pSeg->from[X_IDX]<pNew->bbox.l ) pNew->bbox.l = pSeg->from[X_IDX];
 -           if( pSeg->from[X_IDX]>pNew->bbox.r ) pNew->bbox.r = pSeg->from[X_IDX];
 -           if( pSeg->from[Y_IDX]<pNew->bbox.b ) pNew->bbox.b = pSeg->from[Y_IDX];
 -           if( pSeg->from[Y_IDX]>pNew->bbox.t ) pNew->bbox.t = pSeg->from[Y_IDX];
 -           if( pSeg->to[X_IDX]<pNew->bbox.l ) pNew->bbox.l = pSeg->to[X_IDX];
 -           if( pSeg->to[X_IDX]>pNew->bbox.r ) pNew->bbox.r = pSeg->to[X_IDX];
 -           if( pSeg->to[Y_IDX]<pNew->bbox.b ) pNew->bbox.b = pSeg->to[Y_IDX];
 -           if( pSeg->to[Y_IDX]>pNew->bbox.t ) pNew->bbox.t = pSeg->to[Y_IDX];
 -         }
 -         dx = pNew->bbox.r - pNew->bbox.l;
 -         dy = pNew->bbox.t - pNew->bbox.b;
 -         pNew->area = sqrt(dx*dx+dy*dy);
 -         p->pComptBox = pNew;
 -       }
 -     }
 -   }
 -  
 -   /* Sort the list into order of increasing area */
 -   for(i=0; i<sizeof(aSort)/sizeof(aSort[0]); i++) aSort[i] = 0;
 -   while( p->pComptBox ){
 -     ComptBox *pBox = p->pComptBox;
 -     p->pComptBox = pBox->pNext;
 -     pBox->pNext = 0;
 -     for(i=0; i<sizeof(aSort)/sizeof(aSort[0])-1 && aSort[i]!=0; i++){
 -       pBox = mergeComptBox(aSort[i], pBox);
 -       aSort[i] = 0;
 -     }
 -     aSort[i] = mergeComptBox(aSort[i], pBox);
 -   }
 -   for(i=0; i<sizeof(aSort)/sizeof(aSort[0]); i++){
 -     p->pComptBox = mergeComptBox(aSort[i], p->pComptBox);
 -   }
 - }
 -  
 - /*
 - ** Test to see if the point x,y is contained within the given
 - ** boundary or is on the outside of the boundary.
 - */
 - static int pointWithinBoundary(
 -   Boundary *aBound,      /* The boundary */
 -   int nBound,            /* Number of segments in the boundary */
 -   double x, double y     /* The point to test */
 - ){
 -   int inside = 0;
 -   int i;
 -   for(i=0; i<nBound; i++){
 -     double x0, y0, x1, y1;
 -     Segment *p = aBound[i].pSeg;
 -     x0 = p->from[X_IDX];
 -     y0 = p->from[Y_IDX];
 -     x1 = p->to[X_IDX];
 -     y1 = p->to[Y_IDX];
 -     if( x0==x1 ) continue;
 -     if( (x0>x && x1>x) || (x0<x && x1<x) ) continue;
 -     if( y1 - (x1-x)*(y1-y0)/(x1-x0) >= y ) inside = !inside;
 -   }
 -   return inside;
 - }
 -  
 - /*
 - ** Find a boundary which contains xI, yI.  If the size of the boundary
 - ** is set to 0, that means no such boundary exists.
 - */
 - static int findBoundary(
 -   Wallset *p,             /* The wallset */
 -   double xI, double yI,   /* A point that the boundary should be near */
 -   int nBound,             /* Number of slots available in aBound[] */
 -   Boundary *aBound        /* OUT: Write results here */
 - ){
 -   int n = 0;
 -   ComptBox *pBox;
 -  
 -   buildComptBoxCache(p);
 -   for(pBox=p->pComptBox; pBox; pBox=pBox->pNext){
 -     if( xI<pBox->bbox.l || xI>pBox->bbox.r || yI<pBox->bbox.b || yI>pBox->bbox.t ) continue;
 -     aBound[0] = pBox->prim;
 -     n = completeBoundary(p, 0, nBound, aBound);
 -     if( n>0 && pointWithinBoundary(aBound, n, xI, yI) ) break;
 -     n = 0;
 -   }
 -   return n;
 - }
 -  
 -  
 - /*
 - ** Do an check of the integrity of the internal data structures.  If
 - ** a problem is found, leave an error message in interp->result and
 - ** return TCL_ERROR.  Return TCL_OK if everything is OK.
 - */
 - static int selfCheck(Tcl_Interp *interp, Wallset *p){
 -   Link *pLink;
 -   Segment *pSeg;
 -   int h;
 -   char zErr[200];
 -  
 -   for(pLink=p->pAll; pLink; pLink=pLink->pNext){
 -     pSeg = pLink->pLinkNode;
 -     h = hashInt(pSeg->id);
 -     if(!segmentOnList(pSeg, p->hashId[h]) ){
 -       sprintf(zErr, "segment %d missing from hashId[%d]", pSeg->id, h);
 -       Tcl_SetResult(interp, zErr, TCL_VOLATILE);
 -       return TCL_ERROR;
 -     }
 -     h = hashCoord(pSeg->from[X_IDX], pSeg->from[Y_IDX]);
 -     if(!segmentOnList(pSeg, p->hashFrom[h]) ){
 -       sprintf(zErr, "segment %d missing from hashFrom[%d]", pSeg->id, h);
 -       Tcl_SetResult(interp, zErr, TCL_VOLATILE);
 -       return TCL_ERROR;
 -     }
 -     h = hashCoord(pSeg->to[X_IDX], pSeg->to[Y_IDX]);
 -     if(!segmentOnList(pSeg, p->hashTo[h]) ){
 -       sprintf(zErr, "segment %d missing from hashTo[%d]", pSeg->id, h);
 -       Tcl_SetResult(interp, zErr, TCL_VOLATILE);
 -       return TCL_ERROR;
 -     }
 -   }
 -   return TCL_OK;
 - }
 -  
 - static void Wallset_Delete(ClientData clientData) {
 -   Wallset *p = (Wallset *)clientData;
 -   Link *pLink = p->pAll;
 -   clearComptBoxCache(p);
 -   while( pLink ){
 -     Segment *pSeg = pLink->pLinkNode;
 -     pLink = pSeg->pAll.pNext;
 -     Odie_Free((char *) pSeg );
 -   }
 -   Odie_Free((char *) p );
 - }
 - static int Wallset_Clone(
 -     Tcl_Interp* interp,		/* Tcl interpreter for error reporting */
 -     ClientData metadata,	/* Metadata to be cloned */
 -     ClientData* newMetaData	/* Where to put the cloned metadata */
 - ) {
 -     Tcl_SetObjResult(interp,
 - 		     Tcl_NewStringObj("WALLSETs are not clonable", -1));
 -     /* For now... */
 -     return TCL_ERROR;
 - }
 -  
 -  
 - const static Tcl_ObjectMetadataType WallsetDataType = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "Wallset",
 -   Wallset_Delete,
 -   Wallset_Clone
 - };
 -  
 - /*
 - ** The maximum number of segments in a boundary
 - */
 - #define MX_BOUND 1000
 -  
 - /*
 - ** This routine runs when a method is executed against a wallset.
 - */
 - #define GETWALLSET(OBJCONTEXT)  (Wallset *) Tcl_ObjectGetMetadata(Tcl_ObjectContextObject(objectContext),&WallsetDataType)
 -  
 - static int Wallset_Method_atvertex(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET atvertex X Y
 -   ** title:   Return a list of wall IDs that connect to vertex X,Y
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Link *pList;
 -   double x, y;
 -  
 -   Tcl_Obj *pResult;
 -   if( objc!=4 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X Y");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[1], &x) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &y) ) return TCL_ERROR;
 -   pResult = Tcl_NewObj();
 -   ignoreNone(p);
 -   pList = segmentsAtVertex(p, x*p->rXZoom, y*p->rYZoom);
 -   while( pList ){
 -     Segment *pSeg=pList->pLinkNode;
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->id));
 -     pList = pList->pNext;
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_boundary(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET boundary X Y
 -   ** title:   Return indices of segments forming a boundary around X Y
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Boundary aBound[MX_BOUND];
 -   int nBound;
 -   double x, y;
 -   Tcl_Obj *pResult;
 -   int i;
 -   int showDetail = 0;
 -  
 -   if( objc==5 && strcmp(Tcl_GetStringFromObj(objv[1],0),"-detail")==0 ){
 -     showDetail = 1;
 -     objc--;
 -     objv++;
 -   }
 -   if( objc!=4 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "?-detail? X Y");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[1], &x) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &y) ) return TCL_ERROR; 
 -   nBound = findBoundary(p, x*p->rXZoom, y*p->rYZoom, MX_BOUND, aBound);
 -   if( nBound>MX_BOUND ) nBound = 0;
 -   pResult = Tcl_NewObj();
 -   for(i=0; i<nBound; i++){
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(aBound[i].pSeg->id));
 -     if( showDetail ){
 -       Tcl_ListObjAppendElement(0, pResult,
 -          ODIE_CONSTANT_STRING(aBound[i].backwards ? "right" : "left"));
 -     }
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_closure(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET closure WALLID BACKWARDS CHECKPRIMARY ?-coords?
 -   ** title:   Return the closure of a wall
 -   **
 -   ** The closure is a path of walls going clockwise from the wall given.
 -   ** The return value is a list consisting of wall IDs alternating with
 -   ** keywords "left" or "right" indicating which side of the wall applies.
 -   ** If the CHECKPRIMARY flag is true and the WALLID/BACKWARDS is not the
 -   ** primary wall id for the closure, then return an empty string.  The
 -   ** primary wall id is the wall id with the lowest id number, or if
 -   ** two walls in the closure have the same id, then the one that goes
 -   ** on the right side of the wall.
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Boundary aBound[MX_BOUND];
 -   int id;
 -   int nBound, i, checkPrim;
 -   Tcl_Obj *pResult;
 -   int coordsFlag = 0;
 -   int noerrFlag = 0;
 -   if( objc!=4 && objc!=5 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, 
 -          "WALLID BACKWARDS CHECKPRIMARY ?-coords? ?-noerr?");
 -     return TCL_ERROR;
 -   }
 -   if( objc==5 ){
 -     const char *zOpt = Tcl_GetStringFromObj(objv[4],0);
 -     if( strcmp(zOpt,"-coords")==0 ){
 -       coordsFlag = 1;
 -     }else if( strcmp(zOpt,"-noerr")==0 ){
 -       noerrFlag = 1;
 -     }else{
 -       Tcl_AppendResult(interp, "unknown option: ", zOpt, 0);
 -       return TCL_ERROR;
 -     }
 -   }
 -   if( Tcl_GetIntFromObj(interp, objv[1], &id) ) return TCL_ERROR;
 -   if( (aBound[0].pSeg = findSegment(p, id))==0 ){
 -     Tcl_AppendResult(interp, "segment ",
 -       Tcl_GetStringFromObj(objv[1],0), " does not exist", 0);
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetBooleanFromObj(interp, objv[2], &aBound[0].backwards) ){
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetBooleanFromObj(interp, objv[3], &checkPrim) ){
 -     return TCL_ERROR;
 -   }
 -   ignoreNone(p);
 -   nBound = completeBoundary(p, checkPrim, MX_BOUND, aBound);  
 -   pResult = Tcl_NewObj();
 -   if( nBound<0 && noerrFlag ) nBound = -nBound;
 -   for(i=0; i<nBound; i++){
 -     if( coordsFlag ){
 -       double x, y;
 -       Segment *pSeg = aBound[i].pSeg;
 -       if( aBound[i].backwards ){
 -         x = pSeg->to[X_IDX];
 -         y = pSeg->to[Y_IDX];
 -       }else{
 -         x = pSeg->from[X_IDX];
 -         y = pSeg->from[Y_IDX];
 -       }
 -       Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(x/p->rXZoom));
 -       Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(y/p->rYZoom));
 -     }else{
 -       Tcl_ListObjAppendElement(0, pResult,
 -                                      Tcl_NewIntObj(aBound[i].pSeg->id));
 -       Tcl_ListObjAppendElement(0, pResult,
 -            ODIE_CONSTANT_STRING(aBound[i].backwards ? "right" : "left"));
 -     }
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_comptlist(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET comptlist
 -   ** title:   Return a list of all compartments
 -   **
 -   ** A compartment is a closed circuit of walls.  This routine returns
 -   ** a list of all compartments.  Each element of the list consists of
 -   ** the primary wall for the compartment followed by a bounding box
 -   ** for the compartment.
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   ComptBox *pBox;
 -   Tcl_Obj *pResult = Tcl_NewObj();
 -   buildComptBoxCache(p);
 -   for(pBox=p->pComptBox; pBox; pBox=pBox->pNext){
 -     Tcl_Obj *pElem = Tcl_NewObj();
 -     Tcl_ListObjAppendElement(0, pElem,Tcl_NewIntObj(pBox->prim.pSeg->id));
 -     Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pBox->prim.backwards));
 -     Tcl_ListObjAppendElement(0, pElem, Tcl_NewDoubleObj(pBox->bbox.l/p->rXZoom));
 -     Tcl_ListObjAppendElement(0, pElem, Tcl_NewDoubleObj(pBox->bbox.b/p->rYZoom));
 -     Tcl_ListObjAppendElement(0, pElem, Tcl_NewDoubleObj(pBox->bbox.r/p->rXZoom));
 -     Tcl_ListObjAppendElement(0, pElem, Tcl_NewDoubleObj(pBox->bbox.t/p->rYZoom));
 -     Tcl_ListObjAppendElement(0, pResult, pElem);
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_corners(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET corners X Y
 -   ** title:   Return vertices of compartment containing X,Y
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Boundary aBound[MX_BOUND];
 -   int nBound, i;
 -   double x, y;
 -   Tcl_Obj *pResult;
 -   if( objc!=4 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X Y");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[1], &x) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &y) ) return TCL_ERROR; 
 -   nBound = findBoundary(p, x*p->rXZoom, y*p->rYZoom, MX_BOUND, aBound);
 -   if( nBound>MX_BOUND ) nBound = 0;
 -   pResult = Tcl_NewObj();
 -   for(i=0; i<nBound; i++){
 -     Segment *pSeg = aBound[i].pSeg;
 -     if( aBound[i].backwards ){
 -       x = pSeg->to[X_IDX];
 -       y = pSeg->to[Y_IDX];
 -     }else{
 -       x = pSeg->from[X_IDX];
 -       y = pSeg->from[Y_IDX];
 -     }
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(x/p->rXZoom));
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(y/p->rYZoom));
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_delete(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET delete ID
 -   ** title:   Delete a single segment of a wall given by ID
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int id;
 -   Segment *pSeg;
 -   if( objc!=3 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "ID");
 -     return TCL_ERROR;
 -   }
 -   if( p->busy ){
 -     Tcl_AppendResult(interp, "cannot \"delete\" from within a \"foreach\"",0);
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetIntFromObj(interp, objv[1], &id) ) return TCL_ERROR;
 -   if( (pSeg = findSegment(p, id))==0 ){
 -     Tcl_AppendResult(interp, "segment ",
 -       Tcl_GetStringFromObj(objv[1],0), " does not exist", 0);
 -     return TCL_ERROR;
 -   }
 -   clearComptBoxCache(p);
 -   LinkRemove(&pSeg->pAll);
 -   /* We intentionally do not remove pSeg->pSet because it might not be
 -   ** a well-formed list */
 -   LinkRemove(&pSeg->pHash);
 -   LinkRemove(&pSeg->pFrom);
 -   LinkRemove(&pSeg->pTo);
 -   Odie_Free((char *)pSeg);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_firstboundary(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET firstboundary X Y
 -   ** title:   Find a wall on the boundary of compartment containing X Y
 -   **
 -   ** Returns a list of two elements on success or an empty list if no
 -   ** suitable boundary could be found.  The first element is the ID of a
 -   ** wall that forms part of the boundary for the compartment containing
 -   ** point X,Y.  The second element is TRUE if X,Y is to the right of the
 -   ** wall and false if it is to the left.
 -   **
 -   ** The right/left designation assumes a right-handed coordinate system.
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int isBack;
 -   Segment *pSeg;
 -   double x, y;
 -   int rc;
 -   if( objc!=4 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X Y");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &x) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[3], &y) ) return TCL_ERROR;
 -   ignoreNone(p);
 -   rc = firstBoundarySegment(p, x*p->rXZoom, y*p->rYZoom, &pSeg, &isBack);
 -   if( rc==0 ){
 -     Tcl_Obj *pResult = Tcl_NewObj();
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->id));
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(isBack));
 -     Tcl_SetObjResult(interp, pResult);
 -   }
 -   return TCL_OK;
 - }
 - static int Wallset_Method_foreach(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod: WALLSET foreach CODE
 -   ** title:  Run CODE for each segment of the wallset
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Link *pLink;
 -   int rc = TCL_OK;
 -   if( objc!=2 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "CODE");
 -     return TCL_ERROR;
 -   }
 -   p->busy++;
 -   for(pLink=p->pAll; pLink && rc==TCL_OK; pLink=pLink->pNext){
 -     Segment *pSeg = pLink->pLinkNode;
 -     Tcl_SetVar2Ex(interp, "x0", 0, Tcl_NewDoubleObj(pSeg->from[X_IDX]/p->rXZoom), 0);
 -     Tcl_SetVar2Ex(interp, "y0", 0, Tcl_NewDoubleObj(pSeg->from[Y_IDX]/p->rYZoom), 0);
 -     Tcl_SetVar2Ex(interp, "x1", 0, Tcl_NewDoubleObj(pSeg->to[X_IDX]/p->rXZoom), 0);
 -     Tcl_SetVar2Ex(interp, "y1", 0, Tcl_NewDoubleObj(pSeg->to[Y_IDX]/p->rYZoom), 0);
 -     Tcl_SetVar2Ex(interp, "id", 0, Tcl_NewIntObj(pSeg->id), 0);
 -     Tcl_SetVar2Ex(interp, "lc", 0, Tcl_NewIntObj(pSeg->idLC), 0);
 -     Tcl_SetVar2Ex(interp, "rc", 0, Tcl_NewIntObj(pSeg->idRC), 0);
 -     Tcl_SetVar2Ex(interp, "virtual", 0, Tcl_NewIntObj(pSeg->isBoundary), 0);
 -     rc = Tcl_EvalObjEx(interp, objv[1], 0);
 -   }
 -   if( rc==TCL_BREAK ) rc = TCL_OK;
 -   p->busy--;
 -   return rc;
 - }
 - static int Wallset_Method_info(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod: WALLSET info ID
 -   ** title:  Return information about a single wall segment
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int id;
 -   Segment *pSeg;
 -   Tcl_Obj *pResult;
 -   if( objc!=3 ){
 -     Tcl_WrongNumArgs(interp, 2, objv, "ID");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetIntFromObj(interp, objv[1], &id) ) return TCL_ERROR;
 -   if( (pSeg = findSegment(p, id))==0 ){
 -     Tcl_AppendResult(interp, "segment ",
 -       Tcl_GetStringFromObj(objv[1],0), " does not exist", 0);
 -     return TCL_ERROR;
 -   }
 -   pResult = Tcl_NewObj();
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(pSeg->from[X_IDX]/p->rXZoom));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(pSeg->from[Y_IDX]/p->rYZoom));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(pSeg->to[X_IDX]/p->rXZoom));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(pSeg->to[Y_IDX]/p->rYZoom));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->id));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->idLC));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->idRC));
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_insert(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET insert X0 Y0 X1 Y1 ID LC RC VIRTUAL
 -   ** title:   Create a new wall within the wallset
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int id;
 -   int h,virtual=0;
 -   double x0, y0, x1, y1;
 -   int idLC, idRC;
 -   Segment *pSeg;
 -   if( objc!=8 && objc!=9){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1 ID LC RC ?1|0?");
 -     return TCL_ERROR;
 -   }
 -   if( p->busy ){
 -     Tcl_AppendResult(interp, "cannot \"insert\" from within a \"foreach\"",0);
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[1], &x0) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &y0) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[3], &x1) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[4], &y1) ) return TCL_ERROR;
 -   if( Tcl_GetIntFromObj(interp, objv[5], &id) ) return TCL_ERROR;
 -   if( Tcl_GetIntFromObj(interp, objv[6], &idLC) ) {
 -     Tcl_ResetResult(interp);
 -     idLC=0;
 -   }
 -   if( Tcl_GetIntFromObj(interp, objv[7], &idRC) ) {
 -     Tcl_ResetResult(interp);
 -     idRC=0;
 -   }
 -   if(objc==10) {
 -     if( Tcl_GetIntFromObj(interp, objv[8], &virtual) ) {
 -       Tcl_ResetResult(interp);
 -       virtual=0;
 -     }
 -   }
 -   x0 = roundCoord(x0*p->rXZoom);
 -   y0 = roundCoord(y0*p->rYZoom);
 -   x1 = roundCoord(x1*p->rXZoom);
 -   y1 = roundCoord(y1*p->rYZoom);
 -   if( findSegment(p, id) ){
 -     Tcl_AppendResult(interp, "segment ",
 -       Tcl_GetStringFromObj(objv[6],0), " already exists", 0);
 -     return TCL_ERROR;
 -   }
 -   if( floatCompare(x0,x1)==0 && floatCompare(y0,y1)==0 ){
 -     /* Tcl_AppendResult(interp, "endpoints must be distinct", 0); */
 -     /* return TCL_ERROR; */
 -     return TCL_OK;  /* Not an error.  Just a no-op. */
 -   }
 -   clearComptBoxCache(p);
 -   pSeg = (Segment *)Odie_Alloc( sizeof(*pSeg) );
 -   if( pSeg==0 ) return TCL_ERROR;
 -   pSeg->id = id;
 -   pSeg->idLC = idLC;
 -   pSeg->idRC = idRC;
 -   pSeg->from[X_IDX] = x0;
 -   pSeg->from[Y_IDX] = y0;
 -   pSeg->to[X_IDX] = x1;
 -   pSeg->to[Y_IDX] = y1;
 -   pSeg->isBoundary=virtual;
 -  
 -   LinkInit(pSeg->pAll, pSeg);
 -   LinkInit(pSeg->pSet, pSeg);
 -   LinkInit(pSeg->pHash, pSeg);
 -   LinkInit(pSeg->pFrom, pSeg);
 -   LinkInit(pSeg->pTo, pSeg);
 -   LinkInsert(&p->pAll, &pSeg->pAll);
 -   h = hashInt(id);
 -   LinkInsert(&p->hashId[h], &pSeg->pHash);
 -   h = hashCoord(pSeg->from[X_IDX], pSeg->from[Y_IDX]);
 -   LinkInsert(&p->hashFrom[h], &pSeg->pFrom);
 -   h = hashCoord(pSeg->to[X_IDX], pSeg->to[Y_IDX]);
 -   LinkInsert(&p->hashTo[h], &pSeg->pTo);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_primary(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET primary X Y
 -   ** title:   Return the primary segment of the compartment enclosing X,Y
 -   **
 -   ** The primary segment is the segment with the smallest ID.  If the
 -   ** same segment occurs twice on the list (in other words, if the
 -   ** same compartment is on both sides of a wall), then the right side
 -   ** (as measured facing the direction of travel from x0,y0 -> x1,y1) 
 -   ** is used.
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Boundary aBound[MX_BOUND];
 -  
 -   int nBound;
 -   double x, y;
 -   int i, sideSmallest;
 -   int idSmallest;
 -   Tcl_Obj *pResult;
 -   if( objc!=4 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X Y");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &x) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[3], &y) ) return TCL_ERROR; 
 -   nBound = findBoundary(p, x*p->rXZoom, y*p->rYZoom, MX_BOUND, aBound);
 -   if( nBound>0 && nBound<MX_BOUND ){
 -     idSmallest = aBound[0].pSeg->id;
 -     sideSmallest = aBound[0].backwards;
 -     for(i=1; i<nBound; i++){
 -       if( aBound[i].pSeg->id>idSmallest ) continue;
 -       if( aBound[i].pSeg->id<idSmallest || !sideSmallest ){
 -         idSmallest = aBound[i].pSeg->id;
 -         sideSmallest = aBound[i].backwards;
 -       }
 -     }
 -     pResult = Tcl_NewObj();
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(idSmallest));
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(sideSmallest));
 -     Tcl_SetObjResult(interp, pResult);
 -   }
 -   return TCL_OK;
 - }
 - static int Wallset_Method_intersect(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET intersect X0 Y0 X1 Y1
 -   ** title:   Find the intersection of X0,Y0->X1,Y1 with a segment
 -   **
 -   ** Scan all segments in the wallset looking for one that intersects with
 -   ** a line from X0,Y0 to X1,Y1.  If the intersection occurs at x0,y0, it
 -   ** is ignored, but intersections at x1,y1 count.  If no such intersection
 -   ** exists, return the empty string.  If there are one or more intersections,
 -   ** return the ID of the segment and the X and Y coordinates of the nearest
 -   ** intersection to X0,Y0.  
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   double x0,y0,x1,y1;
 -   double adx, ady;
 -   Link *pI;
 -   int id;
 -   double nx, ny;
 -   double mindist2 = -1.0;
 -   if( objc!=5 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[1], &x0) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &y0) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[3], &x1) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[4], &y1) ) return TCL_ERROR;
 -   x0 = roundCoord(x0*p->rXZoom);
 -   y0 = roundCoord(y0*p->rYZoom);
 -   x1 = roundCoord(x1*p->rXZoom);
 -   y1 = roundCoord(y1*p->rYZoom);
 -   adx = x1-x0;
 -   ady = y1-y0;
 -   if( adx==0.0 && ady==0.0 ) {
 -     return TCL_OK;
 -   }
 -   for(pI=p->pAll; pI; pI=pI->pNext){
 -     double bdx, bdy, denom, num1;
 -     Segment *pSeg;
 -     pSeg = pI->pLinkNode;
 -     bdx = pSeg->to[X_IDX] - pSeg->from[X_IDX];
 -     bdy = pSeg->to[Y_IDX] - pSeg->from[Y_IDX];
 -     denom = adx*bdy - ady*bdx;
 -     num1 = (y0-pSeg->from[Y_IDX])*bdx - (x0-pSeg->from[X_IDX])*bdy;
 -     if( denom==0.0 ){
 -       /* The reference line and segment are parallel */
 -       if( num1==0.0 ){
 -         /* The reference line and segment are colinear */
 -         if( samePoint(x0,y0,pSeg->from[X_IDX],pSeg->from[Y_IDX])
 -                 && adx*bdx<=0.0 && ady*bdy<=0.0 ){
 -           continue;
 -         }
 -         if( samePoint(x0,y0,pSeg->to[X_IDX],pSeg->to[Y_IDX])
 -                 && adx*bdx>=0.0 && ady*bdy>=0.0 ){
 -           continue;
 -         }
 -         if( between(pSeg->from[Y_IDX],y0,y1) && between(pSeg->from[X_IDX],x0,x1) ){
 -           double dx, dy, dist2;
 -           dx = pSeg->from[X_IDX] - x0;
 -           dy = pSeg->from[Y_IDX] - y0;
 -           dist2 = dx*dx + dy*dy;
 -           if( mindist2<0 || mindist2>dist2 ){
 -             mindist2 = dist2;
 -             nx = pSeg->from[X_IDX];
 -             ny = pSeg->from[Y_IDX];
 -             id = pSeg->id;
 -           }
 -         }
 -         if( between(pSeg->to[Y_IDX],y0,y1) && between(pSeg->to[X_IDX],x0,x1) ){
 -           double dx, dy, dist2;
 -           dx = pSeg->to[X_IDX] - x0;
 -           dy = pSeg->to[Y_IDX] - y0;
 -           dist2 = dx*dx + dy*dy;
 -           if( mindist2<0 || mindist2>dist2 ){
 -             mindist2 = dist2;
 -             nx = pSeg->to[X_IDX];
 -             ny = pSeg->to[Y_IDX];
 -             id = pSeg->id;
 -           }
 -         }
 -         if( between(y0,pSeg->from[Y_IDX],pSeg->to[Y_IDX]) && between(x0,pSeg->from[X_IDX],pSeg->to[X_IDX]) ){
 -           if( mindist2<0 || mindist2>0.0 ){
 -             mindist2 = 0.0;
 -             nx = x0;
 -             ny = y0;
 -             id = pSeg->id;
 -           }
 -         }
 -       }
 -     }else{
 -       /* The reference line and segment are not parallel */
 -       double r, s;
 -       r = num1/denom;
 -       s = ((y0-pSeg->from[Y_IDX])*adx - (x0-pSeg->from[X_IDX])*ady)/denom;
 -       if( r>0 && r<=1.0 && s>=0.0 && s<=1.0 ){
 -         double dx, dy, dist2;
 -         dx = r*adx;
 -         dy = r*ady;
 -         dist2 = dx*dx + dy*dy;
 -         if( dist2>=GRAIN && (mindist2<0 || mindist2>dist2) ){
 -           mindist2 = dist2;
 -           nx = x0 + dx;
 -           ny = y0 + dy;
 -           id = pSeg->id;
 -         }
 -       }
 -     }
 -   }
 -   if( mindist2>=0.0 ){
 -     Tcl_Obj *pResult;
 -     pResult = Tcl_NewObj();
 -     nx = roundCoord(nx);
 -     ny = roundCoord(ny);
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(nx/p->rXZoom));
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(ny/p->rYZoom));
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(id));
 -     Tcl_SetObjResult(interp, pResult);
 -   }
 -   return TCL_OK;
 - }
 - static int Wallset_Method_left(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET left ID LC
 -   ** title:   Change the left compartment of a line segment
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int id, idLC;
 -   Segment *pSeg;
 -   if( objc!=3 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "ID LC");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetIntFromObj(interp, objv[1], &id) ) return TCL_ERROR;
 -   if( Tcl_GetIntFromObj(interp, objv[2], &idLC) ) return TCL_ERROR;
 -   if( (pSeg = findSegment(p, id))==0 ){
 -     Tcl_AppendResult(interp, "segment ",
 -       Tcl_GetStringFromObj(objv[2],0), " does not exist", 0);
 -     return TCL_ERROR;
 -   }
 -   pSeg->idLC = idLC;
 -   return TCL_OK;
 - }
 - static int Wallset_Method_list(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod: WALLSET list
 -   ** title:  Return a list of all wall segment identifiers
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Link *pLink;
 -   Tcl_Obj *pResult;
 -   pResult = Tcl_NewObj();
 -   for(pLink=p->pAll; pLink; pLink=pLink->pNext){
 -     Segment *pSeg=pLink->pLinkNode;
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->id));
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_looseends(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET looseends
 -   ** title:   Return a list of walls that are have unconnected ends
 -   **
 -   ** For each unconnected end, the list contains four elements:
 -   **    1.  The wallid
 -   **    2.  0 for the "from" end, "1" for the "to" end
 -   **    3.  The X coordinate of the loose end
 -   **    4.  The Y coordinate of the loose end
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Segment *pSeg;
 -   Link *pAll, *pList;
 -   Tcl_Obj *pRes = Tcl_NewObj();
 -   for(pAll=p->pAll; pAll; pAll=pAll->pNext){
 -     pSeg = pAll->pLinkNode;
 -     pList = segmentsAtVertex(p, pSeg->from[X_IDX], pSeg->from[Y_IDX]);
 -     if( LinkCount(pList)==1 ){
 -       Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(pSeg->id));
 -       Tcl_ListObjAppendElement(0, pRes, ODIE_INT_ZERO());
 -       Tcl_ListObjAppendElement(0, pRes, Tcl_NewDoubleObj(pSeg->from[X_IDX]/p->rXZoom));
 -       Tcl_ListObjAppendElement(0, pRes, Tcl_NewDoubleObj(pSeg->from[Y_IDX]/p->rYZoom));
 -     }
 -     pList = segmentsAtVertex(p, pSeg->to[X_IDX], pSeg->to[Y_IDX]);
 -     if( LinkCount(pList)==1 ){
 -       Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(pSeg->id));
 -       Tcl_ListObjAppendElement(0, pRes, ODIE_INT_ONE());
 -       Tcl_ListObjAppendElement(0, pRes, Tcl_NewDoubleObj(pSeg->to[X_IDX]/p->rXZoom));
 -       Tcl_ListObjAppendElement(0, pRes, Tcl_NewDoubleObj(pSeg->to[Y_IDX]/p->rYZoom));
 -     }
 -   }
 -   Tcl_SetObjResult(interp, pRes);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_nearest(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET nearest vertex|point X Y
 -   ** title:   Find the nearest vertex or point to a point in the plan
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int type;
 -   double x, y, near_x, near_y;
 -   static const char *NEAR_strs[] = { "point", "vertex", 0 };
 -   enum NEAR_enum { NEAR_POINT, NEAR_VERTEX, };
 -   Link *pLink;
 -   Tcl_Obj *pResult;
 -   double dx, dy, dist;
 -  
 -   if( objc!=5 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "point|vertex X Y");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetIndexFromObj(interp, objv[1], NEAR_strs, "option", 0, &type) ){
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &x) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[3], &y) ) return TCL_ERROR;
 -   x *= p->rXZoom;
 -   y *= p->rYZoom;
 -   ignoreNone(p);
 -   if( type==NEAR_POINT ){
 -     pLink = nearestPoint(p, x, y, &near_x, &near_y);
 -   }else if( type==NEAR_VERTEX ){
 -     pLink = nearestVertex(p, x, y, &near_x, &near_y);
 -   }else{
 -     /* Cannot happen */ return TCL_ERROR;
 -   }
 -   if( pLink==0 ) return TCL_OK;  /* There are not segments in the wallset */
 -   pResult = Tcl_NewObj();
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(near_x/p->rXZoom));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(near_y/p->rYZoom));
 -   dx = x - near_x;
 -   dy = y - near_y;
 -   dist = sqrt(dx*dx + dy*dy);
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(dist/p->rXZoom));
 -   Tcl_ListObjAppendElement(0, pResult, Tcl_NewObj());
 -   while( pLink ){
 -     Segment *pSeg=pLink->pLinkNode;
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->id));
 -     pLink = pLink->pNext;
 -   }
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_nextcwwall(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET nextcwwall X0 Y0 X1 Y1
 -   ** title:   Find a wall on X1,Y1 clockwise from X0,Y0->X1,Y1
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int isBack;
 -   Segment *pSeg;
 -   double x0, y0, x1, y1;
 -   int rc;
 -   if( objc!=5 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetDoubleFromObj(interp, objv[1], &x0) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[2], &y0) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[3], &x1) ) return TCL_ERROR;
 -   if( Tcl_GetDoubleFromObj(interp, objv[4], &y1) ) return TCL_ERROR;
 -   x0 = roundCoord(x0*p->rXZoom);
 -   y0 = roundCoord(y0*p->rYZoom);
 -   x1 = roundCoord(x1*p->rXZoom);
 -   y1 = roundCoord(y1*p->rYZoom);
 -   rc = nextCwSegment(p, x0, y0, x1, y1, &pSeg, &isBack);
 -   if( rc==0 ){
 -     Tcl_Obj *pResult = Tcl_NewObj();
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(pSeg->id));
 -     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(isBack));
 -     Tcl_SetObjResult(interp, pResult);
 -   }
 -   return TCL_OK;
 - }
 - static int Wallset_Method_right(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET right ID RC
 -   ** title:   Change the right compartment of a line segment
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   int id, idRC;
 -   Segment *pSeg;
 -   if( objc!=3 ){
 -     Tcl_WrongNumArgs(interp, 1, objv, "ID RC");
 -     return TCL_ERROR;
 -   }
 -   if( Tcl_GetIntFromObj(interp, objv[1], &id) ) return TCL_ERROR;
 -   if( Tcl_GetIntFromObj(interp, objv[2], &idRC) ) return TCL_ERROR;
 -   if( (pSeg = findSegment(p, id))==0 ){
 -     Tcl_AppendResult(interp, "segment ",
 -       Tcl_GetStringFromObj(objv[2],0), " does not exist", 0);
 -     return TCL_ERROR;
 -   }
 -   pSeg->idRC = idRC;
 -   return TCL_OK;
 - }
 - static int Wallset_Method_selfcheck(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET selfcheck
 -   ** title:   Verify the integrity of internal data structures
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   return selfCheck(interp, p);
 - }
 - static int Wallset_Method_zoom(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclmethod:  WALLSET zoom ?ZOOM?
 -   ** title:   Query or change the zoom factor.
 -   */
 -   Wallset *p = GETWALLSET(objectContext);
 -   Tcl_Obj *pResult;
 -   if( objc!=2 && objc!=3 ){
 -     Tcl_WrongNumArgs(interp, 2, objv, "?ZOOM?");
 -     return TCL_ERROR;
 -   }
 -   if( objc==3 ){
 -     double r;
 -     if( Tcl_GetDoubleFromObj(interp, objv[2], &r) ) return TCL_ERROR;
 -     if( r==0.0 ){
 -       Tcl_AppendResult(interp, "zoom must be non-zero", 0);
 -       return TCL_ERROR;
 -     }
 -     p->rYZoom = r;
 -     p->rXZoom = fabs(r);
 -   }
 -   pResult = Tcl_NewDoubleObj(p->rYZoom);
 -   Tcl_SetObjResult(interp, pResult);
 -   return TCL_OK;
 - }
 - static int Wallset_Method_constructor(ClientData clientData ,Tcl_Interp *interp ,Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv)
 - {
 -   /*
 -   ** tclcmd: wallset WALLSET
 -   ** title: Create a new wallset object
 -   ** This routine runs when the "wallset" command is invoked to create a
 -   ** new wallset.
 -   */
 -   Wallset *p;
 -   Tcl_Object thisObject = Tcl_ObjectContextObject(objectContext);
 - 				/* The current connection object */
 -   /*
 -   ** if( objc!=1 ){
 -   **  Tcl_WrongNumArgs(interp, 1, objv, "WALLSET");
 -   **  return TCL_ERROR;
 -   **}
 -   **zCmd = Tcl_GetStringFromObj(objv[1], 0);
 -   */
 -  
 -   p = (Wallset *)Odie_Alloc( sizeof(*p) );
 -   p->rXZoom = 100.0;
 -   p->rYZoom = -100.0;
 -  
 -   Tcl_ObjectSetMetadata(thisObject, &WallsetDataType, (ClientData) p);
 -   return TCL_OK;  
 - }
 - const static Tcl_MethodType WallsetMethodType_atvertex = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "atvertex",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_boundary = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "boundary",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_closure = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "closure",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_comptlist = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "comptlist",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_corners = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "corners",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_delete = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "delete",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_firstboundary = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "firstboundary",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_foreach = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "foreach",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_info = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "info",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_insert = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "insert",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_primary = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "primary",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_intersect = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "intersect",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_left = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "left",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_list = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "list",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_looseends = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "looseends",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_nearest = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "nearest",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_nextcwwall = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "nextcwwall",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_right = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "right",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_selfcheck = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "selfcheck",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_zoom = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "zoom",
 -   NULL,
 -   NULL
 - };
 - const static Tcl_MethodType WallsetMethodType_constructor = {
 -   TCL_OO_METADATA_VERSION_CURRENT,
 -   "constructor",
 -   NULL,
 -   NULL
 - };
 -  
 - int Odie_Wallset_Init(
 -   Tcl_Interp *interp
 - )
 - {
 -  
 -   /*
 -   ** Build the "wallset" class
 -   */
 -   Tcl_Obj* nameObj;		/* Name of a class or method being looked up */
 -   Tcl_Object curClassObject;  /* Tcl_Object representing the current class */
 -   Tcl_Class curClass;		/* Tcl_Class representing the current class */
 -  
 -   /* 
 -    * Find the wallset class, and attach an 'init' method to it.
 -    */
 -  
 -   nameObj = Tcl_NewStringObj("::wallset", -1);
 -   Tcl_IncrRefCount(nameObj);
 -   if ((curClassObject = Tcl_GetObjectFromObj(interp, nameObj)) == NULL) {
 -       Tcl_DecrRefCount(nameObj);
 -       return TCL_ERROR;
 -   }
 -   Tcl_DecrRefCount(nameObj);
 -   curClass = Tcl_GetObjectAsClass(curClassObject);
 -   /* Attach the constructor to the 'connection' class */
 -  
 -   Tcl_ClassSetConstructor(interp, curClass,
 -                           Tcl_NewMethod(interp, curClass, NULL, 1,
 -                                         &WallsetMethodType_constructor, NULL));
 -  
 -    nameObj=Tcl_NewStringObj("atvertex",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_atvertex, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("boundary",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_boundary, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("closure",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_closure, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("comptlist",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_comptlist, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("corners",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_corners, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("delete",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_delete, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("firstboundary",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_firstboundary, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("foreach",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_foreach, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("info",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_info, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("insert",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_insert, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("primary",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_primary, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("intersect",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_intersect, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("left",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_left, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("list",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_list, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("looseends",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_looseends, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("nearest",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_nearest, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("nextcwwall",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_nextcwwall, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("right",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_right, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("selfcheck",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_selfcheck, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -    nameObj=Tcl_NewStringObj("zoom",-1);
 -    Tcl_NewMethod(interp, curClass, nameObj, 1, &WallsetMethodType_zoom, (ClientData) NULL);
 -    Tcl_DecrRefCount(nameObj);
 -   return TCL_OK;
 - }
 -