/*! * \return Object read from file. * \ingroup WlzExtFF * \brief Reads a Woolz object from the given stream using the * stereolithography stl surface file format. This format * has surface definitions defined by a name and a collection * of facet normals and loops. Each facet loop has the * cooordinates of it's vertices. * Only triangulated surface models can be read and all solids * will be treated as one. * \param fP Input file stream. * \param dstErr Destination error number ptr, may be * NULL. */ WlzObject *WlzEffReadObjStl(FILE *fP, WlzErrorNum *dstErr) { int vCnt = 0, inSolid = 0, inFacet = 0, inLoop = 0; char *sav, *str, *tok; WlzDVertex3 vBuf[3]; WlzGMModel *model = NULL; WlzObject *obj = NULL; WlzDomain dom; WlzValues val; WlzErrorNum errNum = WLZ_ERR_NONE; char cBuf[256]; dom.core = NULL; val.core = NULL; if(fP == NULL) { errNum = WLZ_ERR_PARAM_NULL; } else { model = WlzGMModelNew(WLZ_GMMOD_3D, 0, 0, &errNum); } while((errNum == WLZ_ERR_NONE) && ((str = WlzEffReadObjStlRec(fP, cBuf, 256)) != NULL)) { if((tok = strtok_r(str, " \t", &sav)) != NULL) { if(strncmp(tok, "solid", 5) == 0) { if(inSolid == 0) { inSolid = 1; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "facet", 5) == 0) { if((inSolid == 1) && (inFacet == 0)) { inFacet = 1; /* Normal vector is ignored. */ } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "outer", 5) == 0) { if(((tok = strtok_r(NULL, " \t", &sav)) == NULL) || (strncmp(tok, "loop", 4) != 0) || (inSolid == 0) || (inFacet == 0) || (inLoop != 0)) { errNum = WLZ_ERR_READ_INCOMPLETE; } else { vCnt = 0; inLoop = 1; } } else if(strncmp(tok, "vertex", 6) == 0) { char *pTok[3]; if((vCnt < 3) && ((pTok[0] = strtok_r(NULL, " \t", &sav)) != NULL) && ((pTok[1] = strtok_r(NULL, " \t", &sav)) != NULL) && ((pTok[2] = strtok_r(NULL, " \t", &sav)) != NULL) && (sscanf(pTok[0], "%lg", &(vBuf[vCnt].vtX)) == 1) && (sscanf(pTok[1], "%lg", &(vBuf[vCnt].vtY)) == 1) && (sscanf(pTok[2], "%lg", &(vBuf[vCnt].vtZ)) == 1)) { ++vCnt; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "endloop", 7) == 0) { if(inLoop == 1) { inLoop = 0; if(vCnt == 3) { errNum = WlzGMModelConstructSimplex3D(model, vBuf); } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "endfacet", 8) == 0) { if(inFacet == 1) { inFacet = 0; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "endsolid", 8) == 0) { if(inSolid == 1) { inSolid = 0; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } } } /* Create the Woolz object. */ if(errNum == WLZ_ERR_NONE) { if((dom.ctr = WlzMakeContour(&errNum)) != NULL) { dom.ctr->model = WlzAssignGMModel(model, NULL); obj = WlzMakeMain(WLZ_CONTOUR, dom, val, NULL, NULL, &errNum); } } if(errNum != WLZ_ERR_NONE) { if(obj != NULL) { (void )WlzFreeObj(obj); } else if(dom.ctr != NULL) { (void )WlzFreeContour(dom.ctr); } else { (void )WlzGMModelFree(model); } obj = NULL; } if(dstErr) { *dstErr = errNum; } return(obj); }
/*! * \return Object read from file. * \ingroup WlzExtFF * \brief Reads a Woolz object from the given stream using the * stereolithography stl surface file format. This format * has surface definitions defined by a name and a collection * of facet normals and loops. Each facet loop has the * cooordinates of it's vertices. * Only triangulated surface models can be read and all solids * will be treated as one. * \param fP Input file stream. * \param dstErr Destination error number ptr, may be * NULL. */ WlzObject *WlzEffReadObjStl(FILE *fP, WlzErrorNum *dstErr) { int vCnt = 0, inSolid = 0, inFacet = 0, inLoop = 0; char *sav, *str, *tok; WlzDVertex3 vBuf[3]; WlzGMModel *model = NULL; WlzObject *obj = NULL; WlzDomain dom; WlzValues val; WlzErrorNum errNum = WLZ_ERR_NONE; char buf[256]; dom.core = NULL; val.core = NULL; if(fP == NULL) { errNum = WLZ_ERR_PARAM_NULL; } else { model = WlzGMModelNew(WLZ_GMMOD_3D, 0, 0, &errNum); } /* Read just the first 5 bytes, these will contain the string "solid" if * the STL file is ASCII or something else if binary. */ if(fread(buf, sizeof(char), 5, fP) != 5) { errNum = WLZ_ERR_READ_INCOMPLETE; } else { buf[5] = '\0'; if(strncmp(buf, "solid", 5) != 0) /* Binary not ASCII */ { uint32_t tIdx, nT = 0; WlzGreyV tx = {0}; /* Discard the remaining 75 bytes of the 80 byte header block. */ (void )fread(buf, sizeof(char), 75, fP); /* Read number of triangles. */ if(fread(buf, sizeof(char), 4, fP) != 4) { errNum = WLZ_ERR_READ_INCOMPLETE; } else { tx.bytes[0] = buf[0]; tx.bytes[1] = buf[1]; tx.bytes[2] = buf[2]; tx.bytes[3] = buf[3]; nT = (uint32_t)(tx.inv); if(nT < 1) { errNum = WLZ_ERR_READ_INCOMPLETE; } } for(tIdx = 0; (errNum == WLZ_ERR_NONE) && (tIdx < nT); ++tIdx) { if(fread(buf, sizeof(char), 50, fP) != 50) { errNum = WLZ_ERR_READ_INCOMPLETE; } else { int vIdx; size_t bOff = 12; for(vIdx = 0; vIdx < 3; ++vIdx) { tx.bytes[0] = buf[bOff++]; tx.bytes[1] = buf[bOff++]; tx.bytes[2] = buf[bOff++]; tx.bytes[3] = buf[bOff++]; vBuf[vIdx].vtX = tx.flv; tx.bytes[0] = buf[bOff++]; tx.bytes[1] = buf[bOff++]; tx.bytes[2] = buf[bOff++]; tx.bytes[3] = buf[bOff++]; vBuf[vIdx].vtY = tx.flv; tx.bytes[0] = buf[bOff++]; tx.bytes[1] = buf[bOff++]; tx.bytes[2] = buf[bOff++]; tx.bytes[3] = buf[bOff++]; vBuf[vIdx].vtZ = tx.flv; } errNum = WlzGMModelConstructSimplex3D(model, vBuf); } } } else /* ASCII not binary */ { /* Discard rest of the first line. */ (void )WlzEffReadObjStlRec(fP, buf, 256); /* Read and parse ACSII records. */ inSolid = 1; while((errNum == WLZ_ERR_NONE) && ((str = WlzEffReadObjStlRec(fP, buf, 256)) != NULL)) { if((tok = ALC_STRTOK_R(str, " \t", &sav)) != NULL) { if(strncmp(tok, "solid", 5) == 0) { if(inSolid == 0) { inSolid = 1; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "facet", 5) == 0) { if((inSolid == 1) && (inFacet == 0)) { inFacet = 1; /* Normal vector is ignored. */ } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "outer", 5) == 0) { if(((tok = ALC_STRTOK_R(NULL, " \t", &sav)) == NULL) || (strncmp(tok, "loop", 4) != 0) || (inSolid == 0) || (inFacet == 0) || (inLoop != 0)) { errNum = WLZ_ERR_READ_INCOMPLETE; } else { vCnt = 0; inLoop = 1; } } else if(strncmp(tok, "vertex", 6) == 0) { char *pTok[3]; if((vCnt < 3) && ((pTok[0] = ALC_STRTOK_R(NULL, " \t", &sav)) != NULL) && ((pTok[1] = ALC_STRTOK_R(NULL, " \t", &sav)) != NULL) && ((pTok[2] = ALC_STRTOK_R(NULL, " \t", &sav)) != NULL) && (sscanf(pTok[0], "%lg", &(vBuf[vCnt].vtX)) == 1) && (sscanf(pTok[1], "%lg", &(vBuf[vCnt].vtY)) == 1) && (sscanf(pTok[2], "%lg", &(vBuf[vCnt].vtZ)) == 1)) { ++vCnt; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "endloop", 7) == 0) { if(inLoop == 1) { inLoop = 0; if(vCnt == 3) { errNum = WlzGMModelConstructSimplex3D(model, vBuf); } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "endfacet", 8) == 0) { if(inFacet == 1) { inFacet = 0; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } else if(strncmp(tok, "endsolid", 8) == 0) { if(inSolid == 1) { inSolid = 0; } else { errNum = WLZ_ERR_READ_INCOMPLETE; } } } } } } /* Create the Woolz object. */ if(errNum == WLZ_ERR_NONE) { if((dom.ctr = WlzMakeContour(&errNum)) != NULL) { dom.ctr->model = WlzAssignGMModel(model, NULL); obj = WlzMakeMain(WLZ_CONTOUR, dom, val, NULL, NULL, &errNum); } } if(errNum != WLZ_ERR_NONE) { if(obj != NULL) { (void )WlzFreeObj(obj); } else if(dom.ctr != NULL) { (void )WlzFreeContour(dom.ctr); } else { (void )WlzGMModelFree(model); } obj = NULL; } if(dstErr) { *dstErr = errNum; } return(obj); }