/* See {OctfData.h} */ #include /* Last edited on 2009-02-09 18:26:05 by stolfi */ #include #include #include #include #include #include Node_t MakeNode(uint num) { Node_t e = (Node_t)notnull(malloc(sizeof(NodeRec_t)), "no mem"); e->num = num; return e; } Edge_t MakeEdge(uint num) { Edge_t e = (Edge_t)notnull(malloc(sizeof(EdgeRec_t)), "no mem"); e->num = num; return e; } Wall_t MakeWall(uint num) { Wall_t e = (Wall_t)notnull(malloc(sizeof(WallRec_t)), "no mem"); e->num = num; return e; } Cell_t MakeCell(uint num) { Cell_t e = (Cell_t)notnull(malloc(sizeof(CellRec_t)), "no mem"); e->num = num; return e; } Elem_t MakeElem(uint dim, uint num) { switch(dim) { case 0: return (Elem_t)MakeNode(num); case 1: return (Elem_t)MakeEdge(num); case 2: return (Elem_t)MakeWall(num); case 3: return (Elem_t)MakeCell(num); default: demand(FALSE, "bad element dimension"); return NULL; } } Elem_t PElem(Place_t p, uint dim) { switch(dim) { case 0: return (Elem_t)OrgV(p); case 1: return (Elem_t)PEdge(p); case 2: return (Elem_t)PWall(p); case 3: return (Elem_t)PnegP(p); default: demand(FALSE, "bad element dimension"); return NULL; } } void SetElem(Place_t p, uint dim, Elem_t e) { switch(dim) { case 0: SetOrg (p, (Node_t)e); return; case 1: SetEdge(p, (Edge_t)e); return; case 2: SetWall(p, (Wall_t)e); return; case 3: SetPneg(p, (Cell_t)e); return; default: demand(FALSE, "bad element dimension"); } } Edge_t PEdge(Place_t p) { return PWedge(p)->edge; } Wall_t PWall(Place_t p) { return PWedge(p)->wall; } Node_t OrgV(Place_t p) { return (Node_t)PWedge(p)->org[SrotBits(p)]; } Node_t DesV(Place_t p) { return OrgV(Clock(p)); } Cell_t PnegP(Place_t p) { p = Srot(p); return (Cell_t)PWedge(p)->org[SrotBits(p)]; } Cell_t PposP(Place_t p) { return PnegP(Clock(p)); } void SetEdge(Place_t p, Edge_t e) { assert(DualBit(p) == 0); /* [!!! Added by JS. If {p} is dual, should use SetWall instead. !!!] */ PWedge(p)->edge = e; } void SetWall(Place_t p, Wall_t f) { assert(DualBit(p) == 0); /* [!!! Added by JS. If {p} is dual, should use SetEdge instead. !!!] */ PWedge(p)->wall = f; } void SetOrg(Place_t p, Node_t n) { assert(DualBit(p) == 0); /* [!!! Added by JS. If {p} is dual, should use SetPneg instead. !!!] */ PWedge(p)->org[SrotBits(p)] = (NodeOrCell_t)n; } void SetPneg(Place_t p, Cell_t n) { assert(DualBit(p) == 0); /* [!!! Added by JS. If {p} is dual, should use SetOrg instead. !!!] */ p = Srot(p); PWedge(p)->org[SrotBits(p)] = (NodeOrCell_t)n; } void SetPpos(Place_t p, Cell_t n) { assert(DualBit(p) == 0); /* [!!! Added by JS. If {p} is dual, should use SetDes instead. !!!] */ p = Tors(p); PWedge(p)->org[SrotBits(p)] = (NodeOrCell_t)n; } void SetOrgAll(Place_t p, Node_t n) { assert(DualBit(p) == 0); /* [!!! Added by JS. If {p} is dual, should use SetPneg instead. !!!] */ auto bool_t SetOrgOne(Place_t p); EnumPlacesOfElem(Place_vec_make_desc(&p, 1), 0, &SetOrgOne, NULL); bool_t SetOrgOne(Place_t p) { SetOrg(p, n); return FALSE; } } void SetOrgAllN(Place_t p, Node_t n) { Place_t t = p; Place_t tn; do { SetOrg(t, n); tn = Clock(PrevE(t)); do { SetOrg(tn,n); tn = NextF(tn); } while(tn != Clock(PrevE(t))); t = NextF(t); } while (t != p); } void SetOrgAllSame(Place_t p) /* Set alls places with the same origin node that "a". */ { Place_t pn = p; Place_t pp = NextE(PrevF(PrevF(PrevE(p)))); Node_t n = OrgV(p); do { SetOrgAllN(pn,n); pn = ONext(pn); } while (pn != p); do { SetOrgAllN(pp,n); pp = OPrev(pp); } while (pp != NextE(PrevF(PrevF(PrevE(p))))); } void SetPnegOfWall(Place_t p, Cell_t n) { /* [!!! Test below added by JS. If {p} is dual, should use SetOrg instead. !!!] */ assert(DualBit(p) == 1); Place_t t = p; do { SetPneg(t, n); t = PrevE(t); } while (t != p); } void SetPnegOfNearbyWalls(Place_t p, Cell_t n) { /* [!!! Test below added by JS. If {p} is dual, should use SetOrgOfNearbyEdges instead. !!!] */ affirm(DualBit(p) == 1, "wrong duality"); SetPnegOfWall(p,n); Place_t t = p; do { SetPnegOfWall(Clock(PrevF(t)),n); t = PrevE(t); } while (t != p); } void SetPposOfWall(Place_t p, Cell_t n) { assert(DualBit(p) == 1); /* [!!! Added by JS. If {p} is dual, should use SetDes instead. !!!] */ Place_t t = p; do { SetPpos(t, n); t = PrevE(t); } while (t != p); } void SetPposQUX(Place_t p, Cell_t n) { assert(DualBit(p) == 1); /* [!!! Added by JS. If {p} is dual, should use SetDes instead. !!!] */ Place_t t = Clock(p); SetPnegOfNearbyWalls(t,n); do { SetPnegOfNearbyWalls(PrevF(t),n); t = PrevE(t); } while (t != Clock(p)); } void ProvideElemRecords(Place_vec_t root, uint dim, Place_vec_t *vP) { demand(dim <= 3, "invalid dimension for target elements"); /* Set {stp[0..3]} to a permutation of {flp[0..3]} so that {stp[3]==flp[dim]}. So, each orbit of {stp[0..1]} corresponds to one element of dimension {dim}, and vice-versa. */ StepFunc_t stp[4]; stp[0] = &Flip0; stp[1] = &Flip1; stp[2] = &Flip2; stp[3] = &Flip3; /* Permute {stp[0..3]} so that {flp[dim]} is in {stp[3]}; */ /* Try to preserve some sort of dual symmetry. */ uint k = dim; /* Invariant: {stp[k] = flp[dim]}. */ if (k < 2) { /* Swap {stp[i]} with {stp[3-i]} for all {i}: */ StepFunc_t t; t = stp[0]; stp[0] = stp[3]; stp[3] = t; t = stp[1]; stp[1] = stp[2]; stp[2] = t; k = 3 - k; } /* Now the Invariant holds and {k} is {2} or {3}. */ if (k == 2) { /* Swap even and odd elements of {stp[0..3]}: */ StepFunc_t t; t = stp[0]; stp[0] = stp[1]; stp[1] = t; t = stp[3]; stp[3] = stp[2]; stp[2] = t; k = 3; } /* Now the Invariant holds and {k} is {3}. */ uint N = (vP == NULL ? 0 : vP->ne); /* Number of elements seen so far. */ Elem_t eLast = NULL; /* Last element record created, or NULL. */ auto bool_t VisitNewElem(Place_t p); /* Called when {p} is the first place on a new element of dimension {dim}. Creates a new element record, assigns it to {p}'s {dim}-slot (which must be NULL) and increments {N}. */ auto bool_t VisitOldElem(Place_t p); /* Called when {p} is another place on element {eLast}. Merely assigns {eLast} to {p}'s {dim}-slot (which must be NULL or identical to {eLast}). */ /* We should call {visit(p)} only after a {stp[3]} or a new root: */ VisitFunc_t vis[5]; vis[0] = VisitOldElem; vis[1] = VisitOldElem; vis[2] = VisitOldElem; vis[3] = VisitNewElem; vis[4] = VisitNewElem; (void)EnumOrbits(root, 4, stp, vis, NULL); /* Trim the visit list to the true size: */ if (vP != NULL) { Place_vec_trim(vP, N); } /* Return: */ return; bool_t VisitOldElem(Place_t p) { /* This procedure should never be called before {VisitNewElem}: */ assert(eLast != NULL); /* Get the current contents of {p}'s element slot: */ Elem_t e = PElem(p, dim); if (e == NULL) { SetElem(p, dim, eLast); } else { /* Check consistency. Note that we may have set {p.flp[0]} or {p.flp[3]}: */ demand(e == eLast, "element record pointers are not NULL"); } return FALSE; } bool_t VisitNewElem(Place_t p) { /* Get the current contents of {p}'s element slot: */ Elem_t e = PElem(p, dim); if (e == NULL) { /* Create a new element record, store in slot, save in table: */ eLast = MakeElem(dim, N); SetElem(p, dim, eLast); if (vP != NULL) { Place_vec_expand(vP, N); vP->e[N] = p; } N++; } else { /* A record element is already present. Save for checking: */ eLast = e; } return FALSE; } } #define OctfData_C_author \ "The Modula-3 version of this source file was created in 1998" \ "by Luis Arturo Perez Lozada, UNICAMP, inspired on the " \ "Modula-3 implementation of the quad-edge data structure by " \ "J.Stolfi and R.M.Rosi (ca. 1994). " \ "It was converted to C and substantially revised in\n" \ "jan/2007 by J.Stolfi.\n" \ "Modifications:\n" \ " 2007-02-03 Procedures {RenumberEdges}, {RenumberWalls},\n" \ " {RenumberEdgesOutOfNodes} decomissioned;\n" \ " superseded by {EnumOrbits} and its derivatives in {OctfEnum.h}\n" \ " 2007-02-03 Added {ProvideElemRecords}.\n" \ " 2007-02-03 Rewrote {MakeElemTable} to assume that elements records are OK.\n" \ " 2007-02-03 Deleted {Org} and {PnegP}; use {OrgV} and {PnegP} instead.\n" \ " 2007-02-03 Added polymorphic {PElem(p,dim)} and {SetElem(p,dim,e)}."