/*! * \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 A new geometric model. * \ingroup WlzGeoModel * \brief Creates a new geometric model from the given model such * that no elements of the given model which intersect * with elements in the knife model are included. * While this code seems to work for simple models errors * have been seen with complex models. The code for this * function and those static functions that it calls should * be considered "under construction". * \param given Given model. * \param knife Knife model. * \param dstErr Destination error pointer, may be NULL. */ WlzGMModel *WlzGMModelCut(WlzGMModel *given, WlzGMModel *knife, WlzErrorNum *dstErr) { int dim = 2, nBkSz, nHTSz; WlzGMModel *cut = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; const int minBkSz = 1024, minHTSz = 1024; if((given == NULL) || (knife == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(given->type != knife->type) { errNum = WLZ_ERR_DOMAIN_TYPE; } else { switch(given->type) { case WLZ_GMMOD_2I: /* FALLTHROUGH */ case WLZ_GMMOD_2D: /* FALLTHROUGH */ case WLZ_GMMOD_2N: dim = 2; break; case WLZ_GMMOD_3I: /* FALLTHROUGH */ case WLZ_GMMOD_3D: /* FALLTHROUGH */ case WLZ_GMMOD_3N: dim = 3; break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { /* Make a new model. */ if((nBkSz = given->res.vertex.numElm / 16) < minBkSz) { nBkSz = minBkSz; } if((nHTSz = given->res.vertex.numElm) < minHTSz) { nHTSz = minHTSz; } cut = WlzGMModelNew(given->type, nBkSz, nHTSz, &errNum); } if(errNum == WLZ_ERR_NONE) { if(dim == 2) { errNum = WlzGMModelCut2D(cut, given, knife); } else /* dim == 3 */ { errNum = WlzGMModelCut3D(cut, given, knife); } if(errNum != WLZ_ERR_NONE) { (void )WlzGMModelFree(cut); cut = NULL; } } if(dstErr) { *dstErr = errNum; } return(cut); }
/*! * \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); }
int main(int argc, char **argv) { int idR, nRec, nFld, option, ok = 1, usage = 0; FILE *fP = NULL; char *inFileStr, *outObjFileStr; double **bufD = NULL; WlzGMModelType modelType = WLZ_GMMOD_2D; WlzDVertex2 bufD2[2]; WlzDVertex3 bufD3[3]; WlzObject *outObj = NULL; WlzDomain ctrDom; WlzValues dumVal; WlzGMModel *model = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; const char *errMsgStr; static char optList[] = "23diho:"; const char outObjFileStrDef[] = "-", inFileStrDef[] = "-"; opterr = 0; ctrDom.core = NULL; dumVal.core = NULL; outObjFileStr = (char *)outObjFileStrDef; inFileStr = (char *)inFileStrDef; while(ok && ((option = getopt(argc, argv, optList)) != -1)) { switch(option) { case '2': switch(modelType) { case WLZ_GMMOD_2I: /* FALLTHROUGH */ case WLZ_GMMOD_2D: break; case WLZ_GMMOD_3I: modelType = WLZ_GMMOD_2I; break; case WLZ_GMMOD_3D: modelType = WLZ_GMMOD_2D; break; default: break; } break; case '3': switch(modelType) { case WLZ_GMMOD_2I: modelType = WLZ_GMMOD_3I; break; case WLZ_GMMOD_2D: modelType = WLZ_GMMOD_3D; break; case WLZ_GMMOD_3I: /* FALLTHROUGH */ case WLZ_GMMOD_3D: break; default: break; } break; case 'd': switch(modelType) { case WLZ_GMMOD_2I: modelType = WLZ_GMMOD_2D; case WLZ_GMMOD_2D: break; case WLZ_GMMOD_3I: modelType = WLZ_GMMOD_3D; break; case WLZ_GMMOD_3D: break; default: break; } break; case 'i': switch(modelType) { case WLZ_GMMOD_2I: break; case WLZ_GMMOD_2D: modelType = WLZ_GMMOD_2I; break; case WLZ_GMMOD_3I: break; case WLZ_GMMOD_3D: modelType = WLZ_GMMOD_3I; break; default: break; } break; case 'h': usage = 1; ok = 0; break; case 'o': outObjFileStr = optarg; break; default: usage = 1; ok = 0; break; } } if(ok) { if((inFileStr == NULL) || (*inFileStr == '\0') || (outObjFileStr == NULL) || (*outObjFileStr == '\0')) { ok = 0; usage = 1; } if(ok && (optind < argc)) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { inFileStr = *(argv + optind); } } } if(ok) { if((inFileStr == NULL) || (*inFileStr == '\0') || ((fP = (strcmp(inFileStr, "-")? fopen(inFileStr, "r"): stdin)) == NULL) || (AlcDouble2ReadAsci(fP, &bufD, (size_t *) &nRec, (size_t *) &nFld) != ALC_ER_NONE)) { ok = 0; (void )fprintf(stderr, "%s: failed to read from file %s\n", *argv, inFileStr); } if(fP && strcmp(inFileStr, "-")) { fclose(fP); } } if(ok) { ctrDom.ctr = WlzMakeContour(&errNum); if(errNum == WLZ_ERR_NONE) { ctrDom.ctr->model = model = WlzAssignGMModel( WlzGMModelNew(modelType, 0, 0, &errNum), NULL); } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to make contour (%s).\n", argv[0], errMsgStr); } } if(ok) { switch(modelType) { case WLZ_GMMOD_2I: /* FALLTHROUGH */ case WLZ_GMMOD_2D: if(nFld != 4) { ok = 0; } break; case WLZ_GMMOD_3I: /* FALLTHROUGH */ case WLZ_GMMOD_3D: if(nFld != 9) { ok = 0; } break; default: break; } if(ok == 0) { (void )fprintf(stderr, "%s: Failed to read simplicies (syntax error).\n", argv[0]); } } if(ok) { idR = 0; while((errNum == WLZ_ERR_NONE) && (idR < nRec)) { switch(modelType) { case WLZ_GMMOD_2I: /* FALLTHROUGH */ case WLZ_GMMOD_2D: bufD2[0].vtX = *(*(bufD + idR) + 0); bufD2[0].vtY = *(*(bufD + idR) + 1); bufD2[1].vtX = *(*(bufD + idR) + 2); bufD2[1].vtY = *(*(bufD + idR) + 3); errNum = WlzGMModelConstructSimplex2D(model, bufD2); break; case WLZ_GMMOD_3I: /* FALLTHROUGH */ case WLZ_GMMOD_3D: bufD3[0].vtX = *(*(bufD + idR) + 0); bufD3[0].vtY = *(*(bufD + idR) + 1); bufD3[0].vtZ = *(*(bufD + idR) + 2); bufD3[1].vtX = *(*(bufD + idR) + 3); bufD3[1].vtY = *(*(bufD + idR) + 4); bufD3[1].vtZ = *(*(bufD + idR) + 5); bufD3[2].vtX = *(*(bufD + idR) + 6); bufD3[2].vtY = *(*(bufD + idR) + 7); bufD3[2].vtZ = *(*(bufD + idR) + 8); errNum = WlzGMModelConstructSimplex3D(model, bufD3); break; default: break; } ++idR; } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to build model (%s).\n", argv[0], errMsgStr); } } if(ok) { if((fP = (strcmp(outObjFileStr, "-")? fopen(outObjFileStr, "w"): stdout)) == NULL) { ok = 0; (void )fprintf(stderr, "%s: Failed to open output file %s.\n", argv[0], outObjFileStr); } } if(ok) { outObj = WlzMakeMain(WLZ_CONTOUR, ctrDom, dumVal, NULL, NULL, &errNum); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to create output woolz object (%s).\n", argv[0], errMsgStr); } } if(ok) { errNum = WlzWriteObj(fP, outObj); if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to write output object (%s).\n", argv[0], errMsgStr); } } if(bufD) { (void )AlcDouble2Free(bufD); } if(outObj) { (void )WlzFreeObj(outObj); } else if(ctrDom.ctr) { (void )WlzFreeContour(ctrDom.ctr); } if(fP && strcmp(outObjFileStr, "-")) { (void )fclose(fP); } if(usage) { (void )fprintf(stderr, "Usage: %s%s%s%sExample: %s%s", *argv, " [-o<output object>] [-h] [-2] [-3] [-d] [-i] [-o#] \n" " [<input data>]\n" "Version: ", WlzVersion(), "\n" "Options:\n" " -h Prints this usage information.\n" " -o Output object file name.\n" " -2 Build a 2D contour.\n" " -3 Build a 3D contour.\n" " -d Build a contour with double floating point geometry.\n" " -i Build a contour with integer geometry.\n" "Builds a contour from the given input simplicies.\n" "The input data are read from stdin and the output object is written\n" "to stdout unless filenames are given.\n", *argv, " -d -2 -o tri.wlz\n" "0.0 0.0 1.0 0.0\n" "1.0 0.0 0.5 0.866025\n" "0.5 0.866025 0.0 0.0\n" "<eof>\n" "A 2D triangle is built from the three simplicies read from the\n" "standard input and the contour is written to tri.wlz.\n"); } return(!ok); }