/* * Copyright (c) 2011 Hypertriton, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Polyhedron routines. */ #include #include void M_PolyhedronInit(M_Polyhedron *P) { P->nv = 0; P->ne = 0; P->nf = 0; P->v = NULL; P->e = NULL; P->f = NULL; } void M_PolyhedronFree(M_Polyhedron *P) { P->nv = 0; P->ne = 0; P->nf = 0; Free(P->v); P->v = NULL; Free(P->e); P->e = NULL; Free(P->f); P->f = NULL; } int M_PolyhedronRead(AG_DataSource *ds, M_Polyhedron *P) { Uint i, j; P->nv = (Uint)AG_ReadUint32(ds); P->ne = (Uint)AG_ReadUint32(ds); P->nf = (Uint)AG_ReadUint32(ds); if ((P->v = TryMalloc(P->nv*sizeof(M_Vector3))) == NULL || (P->e = TryMalloc(P->ne*sizeof(M_Halfedge))) == NULL || (P->f = TryMalloc(P->nf*sizeof(M_Facet))) == NULL) goto fail; /* Read vertices */ for (i = 0; i < P->nv; i++) P->v[i] = M_ReadVector3(ds); /* Read edges */ for (i = 0; i < P->ne; i+=2) { M_Halfedge *eHead = &P->e[i]; M_Halfedge *eTail = &P->e[i+1]; eHead->v = (Uint)AG_ReadUint32(ds); eTail->v = (Uint)AG_ReadUint32(ds); if (eHead->v >= P->nv || eTail->v >= P->nv) { AG_SetError("Edge%d: Bad vertex %d", i, eHead->v); goto fail; } eHead->f = (Uint)AG_ReadUint32(ds); eTail->f = (Uint)AG_ReadUint32(ds); if (eHead->f >= P->nf || eTail->f >= P->nf) { AG_SetError("Edge%d: Bad facet %d", i, eHead->f); goto fail; } eHead->oe = i+1; eTail->oe = i; } /* Read facets */ for (i = 0; i < P->nf; i++) { M_Facet *f = &P->f[i]; f->n = (Uint)AG_ReadUint8(ds); if ((f->e = TryMalloc(f->n*sizeof(Uint))) == NULL) { goto fail; } for (j = 0; j < f->n; j++) { f->e[j] = (Uint)AG_ReadUint32(ds); if (f->e[j] >= P->ne) { AG_SetError("Facet%d[%d]: Bad incident edge %d", i, j, f->e[j]); goto fail; } } } return (0); fail: return (-1); } void M_PolyhedronWrite(AG_DataSource *ds, const M_Polyhedron *P) { Uint i, j; AG_WriteUint32(ds, (Uint32)P->nv); AG_WriteUint32(ds, (Uint32)P->ne); AG_WriteUint32(ds, (Uint32)P->nf); /* Write vertices */ for (i = 0; i < P->nv; i++) M_WriteVector3(ds, &P->v[i]); /* Write edges */ for (i = 0; i < P->ne; i+=2) { M_Halfedge *eHead = &P->e[i]; M_Halfedge *eTail = &P->e[i+1]; AG_WriteUint32(ds, (Uint32)eHead->v); AG_WriteUint32(ds, (Uint32)eTail->v); AG_WriteUint32(ds, (Uint32)eHead->f); AG_WriteUint32(ds, (Uint32)eTail->f); } /* Write facets */ for (i = 0; i < P->nf; i++) { M_Facet *f = &P->f[i]; AG_WriteUint8(ds, (Uint8)f->n); for (j = 0; j < f->n; j++) AG_WriteUint32(ds, (Uint32)f->e[j]); } } /* * Create a polyhedron vertex. * Return vertex index on success or 0 on failure. */ Uint M_PolyhedronAddVertex(M_Polyhedron *P, M_Vector3 v) { M_Vector3 *vNew; if ((vNew = AG_TryRealloc(P->v, (P->nv+1)*sizeof(M_Vector3))) == NULL) { return (0); } P->v = vNew; P->v[P->nv] = v; return (P->nv++); } /* Remove a vertex from a polyhedron. Vertex must not be in use. */ void M_PolyhedronDelVertex(M_Polyhedron *P, Uint i) { if (i < P->nv) { if (i < P->nv - 1) { memmove(&P->v[i], &P->v[i+1], (P->nv - i - 1)*sizeof(M_Vector3)); } P->nv--; } } /* * Create a polyhedron edge between vertices v1 and v2. The edges are * represented by two contiguous M_Halfedge entries (by convention, * the first halfedge is the HEAD). Returns index of the HEAD halfedge * on success, or 0 on failure. */ Uint M_PolyhedronAddEdge(M_Polyhedron *P, int v1, int v2) { M_Halfedge *eNew; int e1, e2; if ((eNew = AG_TryRealloc(P->e, (P->ne+2)*sizeof(M_Halfedge))) == NULL) { return (0); } P->e = eNew; e1 = P->ne; e2 = P->ne+1; P->e[e1].v = v1; P->e[e2].v = v2; P->e[e1].f = 0; P->e[e2].f = 0; P->e[e1].oe = e2; P->e[e2].oe = e1; return (e1); } /* Remove an edge from a polyhedron. The edge must not be in use. */ void M_PolyhedronDelEdge(M_Polyhedron *P, Uint e) { Uint i = (P->e[e].oe < e) ? P->e[e].oe : e; /* Pick head HE */ if (i < P->ne) { if (i < P->ne - 2) { memmove(&P->e[i], &P->e[i+2], (P->ne - i - 2)*sizeof(M_Halfedge)); } P->ne--; } } /* * Create a polyhedron facet for the specified edges. * Return facet index on success or 0 on failure. */ Uint M_PolyhedronAddFacet(M_Polyhedron *P, Uint n, const Uint *e) { M_Facet *fNew, *f; Uint *eNew; if ((fNew = AG_TryRealloc(P->f, (P->nf+1)*sizeof(M_Facet))) == NULL) { return (0); } if ((eNew = TryMalloc(n*sizeof(Uint))) == NULL) { Free(fNew); return (0); } P->f = fNew; f = &P->f[P->nf]; f->e = eNew; f->n = n; memcpy(f->e, e, n*sizeof(Uint)); return (P->nf++); } /* Remove a facet from a polyhedron. */ void M_PolyhedronDelFacet(M_Polyhedron *P, Uint i) { if (i < P->nv) { Free(P->f[i].e); if (i < P->nf - 1) { memmove(&P->f[i], &P->f[i+1], (P->nf - i - 1)*sizeof(M_Facet)); } P->nf--; } }