SoIndexedFaceSet * Mesh2DView:: Faces2D( SoIndexedFaceSet * faces, WlzErrorNum& errNum) { int nElm = 0; WlzCMeshElm2D *elm; int iFcount = 0; //face index count WlzCMesh2D *mesh=obj->getObj()->domain.cm2; // check if it is 2D mesh and if it has faces if(!(mesh && (mesh->type == WLZ_CMESH_2D) && ((nElm = mesh->res.elm.maxEnt) > 0))) { errNum = WLZ_ERR_DOMAIN_TYPE; } if (errNum == WLZ_ERR_NONE) { for(int i = 0; i < nElm; ++i) { elm = (WlzCMeshElm2D *)AlcVectorItemGet(mesh->res.elm.vec, i); if(elm->idx >= 0) { faces->coordIndex.set1Value(iFcount++, elm->edu[0].nod->idx); faces->coordIndex.set1Value(iFcount++, elm->edu[1].nod->idx); faces->coordIndex.set1Value(iFcount++, elm->edu[2].nod->idx); faces->coordIndex.set1Value(iFcount++, -1); } } } return(faces); }
SoCoordinate3 * Mesh2DView:: Vertices2D( SoCoordinate3 * vertices, WlzErrorNum& errNum) { int nNod = 0; WlzCMeshNod2D *nod; WlzCMesh2D *mesh=obj->getObj()->domain.cm2; if(!(mesh && (mesh->type == WLZ_CMESH_2D) && ((nNod = mesh->res.nod.maxEnt) > 0))) { errNum = WLZ_ERR_DOMAIN_TYPE; } if(errNum == WLZ_ERR_NONE) { /* Output all nodes but use (0, 0, 0) for those that are invalid. */ for(int i = 0; i < nNod; ++i) { nod = (WlzCMeshNod2D *)AlcVectorItemGet(mesh->res.nod.vec, i); if(nod->idx >= 0) { vertices->point.set1Value(i, nod->pos.vtX, nod->pos.vtY, -0.0001); //view mesh in front } else { vertices->point.set1Value(i, 0, 0, 0); } } } return(vertices); }
/*! * \return Woolz error code. * \ingroup WlzGeoModel * \brief Copies elements from the given model to the cut model on * the condition that the elements do not lie within the * knide domain. * It is assumed that the model is a valid 3D model and that * the knife is a valid 3D (plane) domain object. * \param given Given model. * \param knife Knife object. * \param dstErr Destination error pointer, may be NULL. */ static WlzErrorNum WlzGMModelCutDom3D(WlzGMModel *cut, WlzGMModel *given, WlzObject *knife) { WlzPlaneDomain *kDom = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if(knife == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if((cut == NULL) || (given == NULL) || ((kDom = knife->domain.p) == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else { int idF, gMaxF; AlcVector *gFVec; /* For each face of the given model, if it does not intersect a face of * the knife model then add it to the new cut model. */ gMaxF = given->res.face.numIdx; gFVec = given->res.face.vec; for(idF = 0; idF < gMaxF; ++idF) { WlzGMFace *gFace; gFace = (WlzGMFace *)AlcVectorItemGet(gFVec, idF); if(gFace->idx >= 0) { int add; WlzDVertex3 v[3]; (void )WlzGMFaceGetG3D(gFace, v + 0, v + 1, v + 2); add = (WlzInsideDomain3D(kDom, v[0].vtZ, v[0].vtY, v[0].vtX, NULL) == 0) && (WlzInsideDomain3D(kDom, v[1].vtZ, v[1].vtY, v[1].vtX, NULL) == 0) && (WlzInsideDomain3D(kDom, v[2].vtZ, v[2].vtY, v[2].vtX, NULL) == 0); if(add) { /* Given model face does not intersect the knife domain so add it * to the cut model. */ errNum = WlzGMModelConstructSimplex3D(cut, v); } } } } return(errNum); }
/*! * \return Coordinates of center of mass. * \ingroup WlzFeatures * \brief Calculates the centre of mass of a geometric model. * \param model Given geometric model. * \param dstMass Destination pointer for mass, may be * NULL. * \param dstErr Destination pointer for error, may be * NULL. */ static WlzDVertex3 WlzCentreOfMassGM(WlzGMModel *model, double *dstMass, WlzErrorNum *dstErr) { int iCnt, idI = 0, mass = 0; WlzGMVertex *vertex; AlcVector *vec; WlzDVertex3 pos, cMass; WlzErrorNum errNum = WLZ_ERR_NONE; vec = model->res.vertex.vec; iCnt = model->res.vertex.numIdx; cMass.vtX = cMass.vtY = cMass.vtZ = 0.0; while((errNum == WLZ_ERR_NONE) && (iCnt-- > 0)) { vertex = (WlzGMVertex *)AlcVectorItemGet(vec, idI++); if(vertex->idx >= 0) { ++mass; (void )WlzGMVertexGetG3D(vertex, &pos); cMass.vtX += pos.vtX; cMass.vtY += pos.vtY; cMass.vtZ += pos.vtZ; } } if(errNum == WLZ_ERR_NONE) { if(mass > 0) { cMass.vtX /= mass; cMass.vtY /= mass; cMass.vtZ /= mass; } if(dstMass) { *dstMass = (double )mass; } } if(dstErr) { *dstErr = errNum; } return(cMass); }
/*! * \return void * \brief Outputs the mesh and displaced mesh of the given mesh * transform as Postscript to the standard error output. * \param mObj Given mesh transform object. * \param sObj Source object. * \param dilObj Dilated object. * \param outObj Transformed object. */ static void WlzCMeshOutputPS(WlzObject *mObj, WlzObject *sObj, WlzObject *dilObj, WlzObject *outObj) { int idE, idN, useElm; double scale; double *dsp; WlzDVertex2 pos, offset; WlzDVertex2 elmVx[3]; WlzDBox2 bBox; WlzCMeshNod2D *nod; WlzCMeshElm2D *elm; WlzCMesh2D *mesh; WlzIndexedValues *ixv; WlzObject *bObj = NULL; char buf[100]; (void )fprintf(stderr, "%%!\n" "/Times-Courier findfont\n" "1 scalefont\n" "setfont\n" "1 setlinecap\n" "1 setlinejoin\n" "0.01 setlinewidth\n"); if((mObj != NULL) && (mObj->type == WLZ_CMESH_2D) && ((mesh = mObj->domain.cm2) != NULL) && ((ixv = mObj->values.x) != NULL)) { /* Compute the bounding box of the mesh transform. */ bBox.xMin = bBox.yMin = DBL_MAX; bBox.xMax = bBox.yMax = DBL_MIN; for(idN = 0; idN < mesh->res.nod.maxEnt; ++idN) { nod = (WlzCMeshNod2D *)AlcVectorItemGet(mesh->res.nod.vec, idN); if(nod->idx >= 0) { if(nod->pos.vtX < bBox.xMin) { bBox.xMin = nod->pos.vtX; } else if(nod->pos.vtX > bBox.xMax) { bBox.xMax = nod->pos.vtX; } if(nod->pos.vtY < bBox.yMin) { bBox.yMin = nod->pos.vtY; } else if(nod->pos.vtY > bBox.yMax) { bBox.yMax = nod->pos.vtY; } dsp = (double *)WlzIndexedValueGet(ixv, idN); pos.vtX = nod->pos.vtX + dsp[0]; pos.vtY = nod->pos.vtY + dsp[1]; if(pos.vtX < bBox.xMin) { bBox.xMin = pos.vtX; } else if(pos.vtX > bBox.xMax) { bBox.xMax = pos.vtX; } if(pos.vtY < bBox.yMin) { bBox.yMin = pos.vtY; } else if(pos.vtY > bBox.yMax) { bBox.yMax = pos.vtY; } } } if(((pos.vtX = fabs(bBox.xMax - bBox.xMin)) > 1.0) && ((pos.vtY = fabs(bBox.yMax - bBox.yMin)) > 1.0)) { /* Compute scale and offset for an A4 page. */ if((4.0 * pos.vtX) > (3.0 * pos.vtY)) { scale = 500.0 / (bBox.xMax - bBox.xMin); } else { scale = 700.0 / (bBox.yMax - bBox.yMin); } offset.vtX = (bBox.xMin * scale) - 50; offset.vtY = (bBox.yMin * -scale) - 750; (void )fprintf(stderr, "255 0 0 setrgbcolor\n"); for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE) { elm = (WlzCMeshElm2D *)AlcVectorItemGet(mesh->res.elm.vec, idE); if(elm->idx >= 0) { for(idN = 0; idN < 3; ++idN) { pos = elm->edu[idN].nod->pos; elmVx[idN].vtX = (pos.vtX * scale) - offset.vtX; elmVx[idN].vtY = (pos.vtY * -scale) - offset.vtY; } (void )fprintf(stderr, "%g %g moveto " "%g %g lineto " "%g %g lineto " "%g %g lineto " "stroke\n", elmVx[0].vtX, elmVx[0].vtY, elmVx[1].vtX, elmVx[1].vtY, elmVx[2].vtX, elmVx[2].vtY, elmVx[0].vtX, elmVx[0].vtY); WLZ_VTX_2_ADD3(pos, elmVx[0], elmVx[1], elmVx[2]); WLZ_VTX_2_SCALE(pos, pos, 0.333333); (void )sprintf(buf, "%d", elm->idx); (void )fprintf(stderr, "%g %g moveto " "(%s) show\n", pos.vtX, pos.vtY, buf); } } (void )fprintf(stderr, "0 0 255 setrgbcolor\n"); for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE) { elm = (WlzCMeshElm2D *)AlcVectorItemGet(mesh->res.elm.vec, idE); if(elm->idx >= 0) { /* Display only those elements that have all nodes inside the * domain. useElm = ((elm->edg[0].nod->flags | elm->edg[1].nod->flags | elm->edg[2].nod->flags) & WLZ_CMESH_NOD_FLAG_OUTSIDE) == 0; */ useElm = 1; if(useElm) { for(idN = 0; idN < 3; ++idN) { pos = elm->edu[idN].nod->pos; dsp = (double *)WlzIndexedValueGet(ixv, elm->edu[idN].nod->idx); pos.vtX += dsp[0]; pos.vtY += dsp[1]; elmVx[idN].vtX = (pos.vtX * scale) - offset.vtX; elmVx[idN].vtY = (pos.vtY * -scale) - offset.vtY; } (void )fprintf(stderr, "%g %g moveto " "%g %g lineto " "%g %g lineto " "%g %g lineto " "stroke\n", elmVx[0].vtX, elmVx[0].vtY, elmVx[1].vtX, elmVx[1].vtY, elmVx[2].vtX, elmVx[2].vtY, elmVx[0].vtX, elmVx[0].vtY); WLZ_VTX_2_ADD3(pos, elmVx[0], elmVx[1], elmVx[2]); WLZ_VTX_2_SCALE(pos, pos, 0.333333); (void )sprintf(buf, "%d", elm->idx); (void )fprintf(stderr, "%g %g moveto " "(%s) show\n", pos.vtX, pos.vtY, buf); } } } (void )fprintf(stderr, "0 255 0 setrgbcolor\n"); if((bObj = WlzObjToBoundary(sObj, 1, NULL)) != NULL) { WlzBndOutputPS(bObj->domain.b, scale, offset); } (void )fprintf(stderr, "0 255 255 setrgbcolor\n"); if((bObj = WlzObjToBoundary(dilObj, 1, NULL)) != NULL) { WlzBndOutputPS(bObj->domain.b, scale, offset); } (void )fprintf(stderr, "127 0 127 setrgbcolor\n"); if((bObj = WlzObjToBoundary(outObj, 1, NULL)) != NULL) { WlzBndOutputPS(bObj->domain.b, scale, offset); } (void )fprintf(stderr, "showpage\n"); } } }
/*! * \return Woolz error number. * \ingroup WlzExtFF * \brief Writes the given Woolz object (which is known to be a * WLZ_CONTOUR) to the given file stream using the * stereolithography stl file format, see WlzEffReadObjStl(). * \param fP Output file stream. * \param obj Given woolz object (must not be NULL). */ static WlzErrorNum WlzEffWriteObjCtrStl(FILE *fP, WlzObject *obj) { int nFce, nVtx; WlzGMModel *model; WlzGMResIdxTb *resIdxTb = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if((obj->domain.core == NULL) || ((model = obj->domain.ctr->model) == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else { switch(model->type) { case WLZ_GMMOD_3I: /* FALLTHROUGH */ case WLZ_GMMOD_3D: /* FALLTHROUGH */ case WLZ_GMMOD_3N: break; default: errNum = WLZ_ERR_DOMAIN_TYPE; break; } } /* Check there are verticies and faces. */ if(errNum == WLZ_ERR_NONE) { if((model->res.vertex.numElm < 3) || ((nFce = model->res.face.numElm) < 1)) { errNum = WLZ_ERR_DOMAIN_DATA; } } if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "solid ascii\n") <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } if(errNum == WLZ_ERR_NONE) { int idF; WlzGMFace *fce; AlcVector *vec; WlzDVertex3 nrm; WlzDVertex3 vBuf[3]; vec = model->res.face.vec; for(idF = 0; idF < model->res.face.numIdx; ++idF) { fce = (WlzGMFace *)AlcVectorItemGet(vec, idF); if(fce->idx >= 0) { errNum = WlzGMFaceGetG3D(fce, vBuf + 0, vBuf + 1, vBuf + 2); if(errNum == WLZ_ERR_NONE) { nrm = WlzGeomTriangleNormal(vBuf[0], vBuf[1], vBuf[2]); if(fprintf(fP, " facet normal %g %g %g\n" " outer loop\n" " vertex %g %g %g\n" " vertex %g %g %g\n" " vertex %g %g %g\n" " endloop\n" " endfacet\n", nrm.vtX, nrm.vtY, nrm.vtZ, vBuf[0].vtX, vBuf[0].vtY, vBuf[0].vtZ, vBuf[1].vtX, vBuf[1].vtY, vBuf[1].vtZ, vBuf[2].vtX, vBuf[2].vtY, vBuf[2].vtZ) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } } WlzGMModelResIdxFree(resIdxTb); if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "endsolid\n") <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } return(errNum); }
/*! * \return Woolz error number. * \ingroup WlzExtFF * \brief Writes the given Woolz object (which is known to be a * WLZ_CMESH_2D5) object to the given file stream using the * stereolithography stl file format, see WlzEffReadObjStl(). * \param fP Output file stream. * \param obj Given woolz object (must not be NULL). */ static WlzErrorNum WlzEffWriteObjCM2D5Stl(FILE *fP, WlzObject *obj) { int *nodTbl = NULL; WlzCMesh2D5 *mesh; WlzErrorNum errNum = WLZ_ERR_NONE; if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { mesh = obj->domain.cm2d5; if(mesh->type != WLZ_CMESH_2D5) { errNum = WLZ_ERR_DOMAIN_TYPE; } } if(errNum == WLZ_ERR_NONE) { if((nodTbl = (int *)AlcMalloc(mesh->res.nod.maxEnt * sizeof(int))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "solid ascii\n") <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } /* Output the elements. */ if(errNum == WLZ_ERR_NONE) { int idE; WlzDVertex3 nrm; WlzCMeshElm2D5 *elm; WlzCMeshNod2D5 *nod[3]; for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE) { elm = (WlzCMeshElm2D5 *)AlcVectorItemGet(mesh->res.elm.vec, idE); if(elm->idx >= 0) { WlzCMeshElmGetNodes2D5(elm, nod + 0, nod + 1, nod + 2); nrm = WlzGeomTriangleNormal(nod[0]->pos, nod[1]->pos, nod[2]->pos); if(fprintf(fP, " facet normal %g %g %g\n" " outer loop\n" " vertex %g %g %g\n" " vertex %g %g %g\n" " vertex %g %g %g\n" " endloop\n" " endfacet\n", nrm.vtX, nrm.vtY, nrm.vtZ, nod[0]->pos.vtX, nod[0]->pos.vtY, nod[0]->pos.vtZ, nod[1]->pos.vtX, nod[1]->pos.vtY, nod[1]->pos.vtZ, nod[2]->pos.vtX, nod[2]->pos.vtY, nod[2]->pos.vtZ) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "endsolid\n") <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } return(errNum); }
/*! * \return Object read from file. * \ingroup WlzExtFF * \brief Reads a Woolz object from the given stream using the * GRUMMP vmesh tetrahedral mesh file format. * \param fP Input file stream. * \param dstErr Destination error number ptr, may be * NULL. */ WlzObject *WlzEffReadObjEMT(FILE *fP, WlzErrorNum *dstErr) { int nElm = 0, nNod = 0; char *str; WlzDVertex3 *vBuf = NULL; WlzCMesh3D *mesh = NULL; WlzObject *obj = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; char cBuf[256]; if(fP == NULL) { errNum = WLZ_ERR_PARAM_NULL; } else { int idC = 0; /* Optional records may be comments starting with a '#' but apart * from these the first line should have a single integer specifying * the number of nodes. */ do { if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; } else if(*str != '#') { if((idC = sscanf(str, "%d", &nNod)) != 1) { errNum = WLZ_ERR_READ_INCOMPLETE; } } } while((errNum == WLZ_ERR_NONE) && (idC != 1)); } /* Check for reasonable number of nodes. */ if(errNum == WLZ_ERR_NONE) { if(nNod <= 0) { errNum = WLZ_ERR_READ_INCOMPLETE; } } /* Create a new 3D constrained mesh. */ if(errNum == WLZ_ERR_NONE) { mesh = WlzCMeshNew3D(&errNum); } /* Read in the node positions into a temporary buffer computing their * bounding box and then create the nodes. */ if(errNum == WLZ_ERR_NONE) { if((vBuf = AlcMalloc(sizeof(WlzDVertex3) * nNod)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { int idN = 0; while(idN < nNod) { if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else if(*str != '#') { if(sscanf(str, "%lg %lg %lg", &(vBuf[idN].vtX), &(vBuf[idN].vtY), &(vBuf[idN].vtZ)) != 3) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } ++idN; } } } if(errNum == WLZ_ERR_NONE) { mesh->bBox = WlzBoundingBoxVtx3D(nNod, vBuf, NULL); if(AlcVectorExtendAndGet(mesh->res.nod.vec, nNod) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } if(errNum == WLZ_ERR_NONE) { errNum = WlzCMeshReassignGridCells3D(mesh, nNod); } if(errNum == WLZ_ERR_NONE) { int idN; for(idN = 0; idN < nNod; ++idN) { (void )WlzCMeshNewNod3D(mesh, vBuf[idN], NULL); } } AlcFree(vBuf); /* Read the number of elements in the mesh. */ if(errNum == WLZ_ERR_NONE) { int idC = 0; /* Optional records may be comments starting with a '#' but apart * from these the first line should have a single integer specifying * the number of nodes. */ do { if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; } else if(*str != '#') { if((idC = sscanf(str, "%d", &nElm)) != 1) { errNum = WLZ_ERR_READ_INCOMPLETE; } } } while((errNum == WLZ_ERR_NONE) && (idC != 1)); } /* Check for reasonable number of elements. */ if(errNum == WLZ_ERR_NONE) { if(nElm <= 0) { errNum = WLZ_ERR_READ_INCOMPLETE; } } /* Allocate room for the elements in the mesh. */ if(errNum == WLZ_ERR_NONE) { if(AlcVectorExtendAndGet(mesh->res.elm.vec, nElm) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Read the elements adding them to the mesh. */ if(errNum == WLZ_ERR_NONE) { int idE = 0; while(idE < nElm) { if((str = WlzEffReadObjEMTRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else if(*str != '#') { int dummyI; int nIdx[4]; WlzCMeshNod3D *nBuf[4]; if((sscanf(str, "%d %d %d %d %d", &dummyI, &(nIdx[0]), &(nIdx[1]), &(nIdx[2]), &(nIdx[3])) != 5) || (nIdx[0] <= 0) || (nIdx[0] > nNod) || (nIdx[1] <= 0) || (nIdx[1] > nNod) || (nIdx[2] <= 0) || (nIdx[2] > nNod) || (nIdx[3] <= 0) || (nIdx[3] > nNod)) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else { int idN; for(idN = 0; idN < 4; ++idN) { nBuf[idN] = (WlzCMeshNod3D *) AlcVectorItemGet(mesh->res.nod.vec, nIdx[idN] - 1); } (void )WlzCMeshNewElm3D(mesh, nBuf[0], nBuf[1], nBuf[3], nBuf[2], 1, &errNum); if(errNum != WLZ_ERR_NONE) { break; } ++idE; } } } } /* Ignore the boundary faces in the file, they're redundant information. */ if(errNum == WLZ_ERR_NONE) { WlzDomain dom; WlzValues val; val.core = NULL; dom.cm3 = mesh; WlzCMeshDelUnusedNodes3D(mesh); WlzCMeshUpdateMaxSqEdgLen3D(mesh); obj = WlzMakeMain(WLZ_CMESH_3D, dom, val, NULL, NULL, &errNum); } if(errNum != WLZ_ERR_NONE) { (void )WlzCMeshFree3D(mesh); } if(dstErr) { *dstErr = errNum; } return(obj); }
/*! * \return Woolz error number. * \ingroup WlzExtFF * \brief Writes the given Woolz object to the given stream using the * Netgen neutral mesh file format. * \param fP Output file stream. * \param obj Given woolz object. */ WlzErrorNum WlzEffWriteObjEMT(FILE *fP, WlzObject *obj) { int nBFce = 0, nElm = 0, nNod = 0; int *nodTbl = NULL; WlzCMesh3D *mesh; WlzErrorNum errNum = WLZ_ERR_NONE; if(fP == NULL) { errNum = WLZ_ERR_PARAM_NULL; } else if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(obj->type != WLZ_CMESH_3D) { errNum = WLZ_ERR_OBJECT_TYPE; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { mesh = obj->domain.cm3; if(mesh->type != WLZ_CMESH_3D) { errNum = WLZ_ERR_DOMAIN_TYPE; } } if(errNum == WLZ_ERR_NONE) { if((nodTbl = (int *) AlcMalloc(mesh->res.nod.maxEnt * sizeof(int))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Compute the number of boundary faces while building an element table to * avoid deleted elements. */ if(errNum == WLZ_ERR_NONE) { int idE; nNod = mesh->res.nod.numEnt; for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE) { WlzCMeshElm3D *elm; elm = (WlzCMeshElm3D *)AlcVectorItemGet(mesh->res.elm.vec, idE); if(elm->idx >= 0) { int idF; for(idF = 0; idF < 4; ++idF) { if((elm->face[idF].opp == NULL) || (elm->face[idF].opp == &(elm->face[idF]))) { ++nBFce; } } ++nElm; } } } /* Output the number of nodes. */ if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "%d\n", nNod) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } /* Output the node positions while building a node table to avoid deleted * nodes. */ if(errNum == WLZ_ERR_NONE) { int idC = 0, idN; for(idN = 0; idN < mesh->res.nod.maxEnt; ++idN) { WlzCMeshNod3D *nod; nod = (WlzCMeshNod3D *)AlcVectorItemGet(mesh->res.nod.vec, idN); if(nod->idx >= 0) { nodTbl[idN] = ++idC; if(fprintf(fP, " %lg %lg %lg\n", nod->pos.vtX, nod->pos.vtY, nod->pos.vtZ) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } /* Output the number of elements. */ if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "%d\n", nElm) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } /* Output the elements using the node indices. */ if(errNum == WLZ_ERR_NONE) { int idE; WlzCMeshNod3D *nBuf[4]; for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE) { WlzCMeshElm3D *elm; elm = (WlzCMeshElm3D *)AlcVectorItemGet(mesh->res.elm.vec, idE); if(elm->idx >= 0) { WlzCMeshElmGetNodes3D(elm, &(nBuf[0]), &(nBuf[1]), &(nBuf[2]), &(nBuf[3])); if(fprintf(fP, " 1 %d %d %d %d\n", nodTbl[(nBuf[0])->idx], nodTbl[(nBuf[1])->idx], nodTbl[(nBuf[2])->idx], nodTbl[(nBuf[3])->idx]) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } /* Output the number of boundary faces. */ if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "%d\n", nBFce) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } /* Output the boundary faces defined by the node indices. */ if(errNum == WLZ_ERR_NONE) { int idE; for(idE = 0; idE < mesh->res.elm.maxEnt; ++idE) { WlzCMeshElm3D *elm; elm = (WlzCMeshElm3D *)AlcVectorItemGet(mesh->res.elm.vec, idE); if(elm->idx >= 0) { int idF; for(idF = 0; idF < 4; ++idF) { WlzCMeshFace *fce; fce = elm->face + idF; if((fce->opp == NULL) || (fce->opp == fce)) { WlzCMeshEdgU3D *edu; edu = fce->edu; if(fprintf(fP, " 1 %d %d %d\n", nodTbl[edu->nod->idx], nodTbl[edu->next->nod->idx], nodTbl[edu->next->next->nod->idx]) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } if(errNum != WLZ_ERR_NONE) { break; } } } AlcFree(nodTbl); return(errNum); }
/*! * \return Woolz error code. * \ingroup BinWlzApp * \brief Outputs a VTK tensor file from a conforming mesh object. * \param prog: Program name. * \param inFileStr Name of input file object was read * from. * \param fP Opened file. * \param obj Given conforming mesh object. */ static WlzErrorNum WlzVTKTensorFromCMesh(char *prog, char *inFileStr, FILE *fP, WlzObject *obj) { int idE, maxElm; WlzCMesh3D *mesh; AlcVector *elmVec; WlzIndexedValues *ixv; WlzErrorNum errNum = WLZ_ERR_NONE; mesh = obj->domain.cm3; ixv = obj->values.x; elmVec = mesh->res.elm.vec; maxElm = mesh->res.elm.maxEnt; if(fprintf(fP, "# vtk DataFile Version 1.0\n" "Output from Woolz WLZ_CMESH_3D file %s via %s\n" "ASCII\n" "DATASET POLYDATA\n" "POINTS %d float\n", inFileStr, prog, maxElm) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } if(errNum == WLZ_ERR_NONE) { for(idE = 0; idE < maxElm; ++idE) { WlzDVertex3 c; WlzCMeshElm3D *elm; WlzCMeshNod3D *nod[4]; elm = (WlzCMeshElm3D *)AlcVectorItemGet(elmVec, idE); if(elm->idx >= 0) { nod[0] = WLZ_CMESH_ELM3D_GET_NODE_0(elm); nod[1] = WLZ_CMESH_ELM3D_GET_NODE_1(elm); nod[2] = WLZ_CMESH_ELM3D_GET_NODE_2(elm); nod[3] = WLZ_CMESH_ELM3D_GET_NODE_2(elm); c.vtX = 0.25 * (nod[0]->pos.vtX + nod[1]->pos.vtX + nod[2]->pos.vtX + nod[3]->pos.vtX); c.vtY = 0.25 * (nod[0]->pos.vtY + nod[1]->pos.vtY + nod[2]->pos.vtY + nod[3]->pos.vtY); c.vtZ = 0.25 * (nod[0]->pos.vtZ + nod[1]->pos.vtZ + nod[2]->pos.vtZ + nod[3]->pos.vtZ); } else { WLZ_VTX_3_ZERO(c); } if(fprintf(fP, "%f %f %f\n", c.vtX, c.vtY, c.vtZ) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "POINT_DATA %d\n" "TENSORS tensors float\n", maxElm) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } if(errNum == WLZ_ERR_NONE) { for(idE = 0; idE < maxElm; ++idE) { WlzCMeshElm3D *elm; elm = (WlzCMeshElm3D *)AlcVectorItemGet(elmVec, idE); if(elm->idx >= 0) { double *t; t = (double *)WlzIndexedValueGet(ixv, elm->idx); if(fprintf(fP, "%f %f %f " "%f %f %f " "%f %f %f \n", t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8]) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } else { if(fprintf(fP, "0 0 0\n" "0 0 0\n" "0 0 0\n\n") <= 0) errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } return(errNum); }
/*! * \return Woolz error code. * \ingroup WlzGeoModel * \brief Copies elements from the given model to the cut model on * the condition that the elements do not intersects any * elements of the knide model. * All models are assumed to be valid 3D models. * \param given Given model. * \param knife Knife model. * \param dstErr Destination error pointer, may be NULL. */ static WlzErrorNum WlzGMModelCut3D(WlzGMModel *cut, WlzGMModel *given, WlzGMModel *knife) { WlzGMGridWSp3D *kGrid = NULL; WlzErrorNum errNum = WLZ_ERR_NONE; if((cut == NULL) || (knife == NULL) || (given == NULL)) { errNum = WLZ_ERR_DOMAIN_NULL; } else { int cutDim, givenDim, knifeDim; cutDim = WlzGMModelGetDimension(cut, NULL); givenDim = WlzGMModelGetDimension(given, NULL); knifeDim = WlzGMModelGetDimension(knife, NULL); if((cutDim != 3) || (givenDim != 3) || (knifeDim != 3)) { errNum = WLZ_ERR_DOMAIN_TYPE; } } /* Create a cell grid workspace for the knife model. */ if(errNum == WLZ_ERR_NONE) { kGrid = WlzGeoModelGridWSpNew3D(knife, WLZ_GMELM_FACE, &errNum); } /* For each face of the given model, if it does not intersect a face of * the knife model then add it to the new cut model. */ if(errNum == WLZ_ERR_NONE) { int idF, idX, idY, idZ, gMaxF; AlcVector *gFVec; gMaxF = given->res.face.numIdx; gFVec = given->res.face.vec; for(idF = 0; idF < gMaxF; ++idF) { WlzGMFace *gFace; gFace = (WlzGMFace *)AlcVectorItemGet(gFVec, idF); if(gFace->idx >= 0) { int add = 1; WlzDVertex3 gVtx[3]; WlzIBox3 cBox; WlzDBox3 fBox; (void )WlzGMFaceGetG3D(gFace, gVtx + 0, gVtx + 1, gVtx + 2); fBox = WlzBoundingBoxVtx3D(3, gVtx, NULL); cBox = WlzGeoModelGridCellsInDBox(kGrid, fBox); /* For each cell that the bonding box intersects. */ for(idZ = cBox.zMin; idZ <= cBox.zMax; ++idZ) { WlzDVertex3 kCellMin, kCellMax; kCellMin.vtZ = kGrid->org.vtZ + kGrid->cellSz * idZ; kCellMax.vtZ = kGrid->org.vtZ + kGrid->cellSz * (idZ + 1); for(idY = cBox.yMin; idY <= cBox.yMax; ++idY) { kCellMin.vtY = kGrid->org.vtY + kGrid->cellSz * idY; kCellMax.vtY = kGrid->org.vtY + kGrid->cellSz * (idY + 1); for(idX = cBox.xMin; idX <= cBox.xMax; ++idX) { WlzDVertex3 kVtx[3]; WlzGMGridWSpCell3D *kCell; kCellMin.vtX = kGrid->org.vtX + kGrid->cellSz * idX; kCellMax.vtX = kGrid->org.vtX + kGrid->cellSz * (idX + 1); /* Test if the face of the given model intersects the faces * of the knife grid cells. */ kCell = *(*(*(kGrid->cells + idZ) + idY) + idX); while(kCell != NULL) { WlzGMFace *kFace; kFace = kCell->elem.face; (void )WlzGMFaceGetG3D(kFace, kVtx + 0, kVtx + 1, kVtx + 2); if(WlzGeomTriangleTriangleIntersect3D( gVtx[0], gVtx[1], gVtx[2], kVtx[0], kVtx[1], kVtx[2]) != 0) { add = 0; idX = cBox.xMax + 1; /* Break from these loops. */ idY = cBox.yMax + 1; idZ = cBox.zMax + 1; break; } if(errNum != WLZ_ERR_NONE) { goto RETURN; } kCell = kCell->next; } } } } if(add) { /* Given model face does not intersect the knife model face * so just add it to the cut model. */ errNum = WlzGMModelConstructSimplex3D(cut, gVtx); } } } } RETURN: if(kGrid) { (void )WlzGeoModelGridFree3D(kGrid); } return(errNum); }
/*! * \return Woolz error code. * \brief Prints boundary node coordinates for a conforming mesh. * \param fP File pointer opened for acsii write. * \param obj Object containing the conforming mesh. */ static WlzErrorNum WlzBoundaryVerticesCMesh(FILE *fP, WlzObject *obj) { WlzErrorNum errNum = WLZ_ERR_NONE; if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else { int idx, mN; WlzCMeshP mesh; AlcVector *vec; switch(obj->type) { case WLZ_CMESH_2D: mesh.m2 = obj->domain.cm2; mN = mesh.m2->res.nod.maxEnt; vec = mesh.m2->res.nod.vec; for(idx = 0; idx < mN; ++idx) { WlzCMeshNod2D *nod; nod = (WlzCMeshNod2D *)AlcVectorItemGet(vec, idx); if(nod->idx >= 0) { if(WlzCMeshNodIsBoundary2D(nod)) { (void )fprintf(fP, "%lg %lg\n", nod->pos.vtX, nod->pos.vtY); } } } break; case WLZ_CMESH_2D5: mesh.m2d5 = obj->domain.cm2d5; mN = mesh.m2d5->res.nod.maxEnt; vec = mesh.m2d5->res.nod.vec; for(idx = 0; idx < mN; ++idx) { WlzCMeshNod2D5 *nod; nod = (WlzCMeshNod2D5 *)AlcVectorItemGet(vec, idx); if(nod->idx >= 0) { if(WlzCMeshNodIsBoundary2D5(nod)) { (void )fprintf(fP, "%lg %lg %lg\n", nod->pos.vtX, nod->pos.vtY, nod->pos.vtZ); } } } break; case WLZ_CMESH_3D: mesh.m3 = obj->domain.cm3; mN = mesh.m3->res.nod.maxEnt; vec = mesh.m3->res.nod.vec; for(idx = 0; idx < mN; ++idx) { WlzCMeshNod3D *nod; nod = (WlzCMeshNod3D *)AlcVectorItemGet(vec, idx); if(nod->idx >= 0) { if(WlzCMeshNodIsBoundary3D(nod)) { (void )fprintf(fP, "%lg %lg %lg\n", nod->pos.vtX, nod->pos.vtY, nod->pos.vtZ); } } } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } if((errNum == WLZ_ERR_NONE) && feof(fP)) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } return(errNum); }
/*! * \return Woolz error number. * \ingroup WlzExtFF * \brief Writes the given Woolz object to a pair of files * using the node/ele two part mesh file format. The * given file name is used to generate the '.node' and '.ele' * filenames. * \param gvnFileName Given file name with '.node' or * no extension. * \param obj Given woolz object. */ WlzErrorNum WlzEffWriteObjNodeEle(const char *gvnFileName, WlzObject *obj) { int cnt, idE, idN, bnd = 0, dim = 0, nElm = 0, nNod = 0, maxElm = 0, maxNod = 0; char *fileName = NULL, *nodeFileName = NULL, *eleFileName = NULL; int *nodTbl = NULL; FILE *fP = NULL; WlzCMeshP mesh; WlzCMeshElm2D *elm2; WlzCMeshElm3D *elm3; WlzCMeshNod2D *nod2[4]; WlzCMeshNod3D *nod3[4]; WlzErrorNum errNum = WLZ_ERR_NONE; mesh.v = NULL; if(obj == NULL) { errNum = WLZ_ERR_OBJECT_NULL; } else if(obj->domain.core == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if((gvnFileName == NULL) || (*gvnFileName == '\0')) { errNum = WLZ_ERR_PARAM_NULL; } else { errNum = WlzEffNodeEleFileNames(&fileName, &nodeFileName, &eleFileName, gvnFileName); } /* Open the node file. */ if(errNum == WLZ_ERR_NONE) { if((nodeFileName == NULL) || (*nodeFileName == '\0') || ((fP = fopen(nodeFileName, "w")) == NULL)) { errNum = WLZ_ERR_READ_EOF; } #ifdef _WIN32 if(fP != NULL) { if(_setmode(_fileno(fP), 0x8000) == -1) { errNum = WLZ_ERR_READ_EOF; } } #endif } if(errNum == WLZ_ERR_NONE) { switch(obj->type) { case WLZ_CMESH_2D: if((mesh.m2 = obj->domain.cm2) == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(mesh.m2->type == WLZ_CMESH_2D) { dim = 2; nNod = mesh.m2->res.nod.numEnt; nElm = mesh.m2->res.elm.numEnt; maxNod = mesh.m2->res.nod.maxEnt; maxElm = mesh.m2->res.elm.maxEnt; } else { errNum = WLZ_ERR_DOMAIN_TYPE; } break; case WLZ_CMESH_3D: if((mesh.m3 = obj->domain.cm3) == NULL) { errNum = WLZ_ERR_DOMAIN_NULL; } else if(mesh.m3->type == WLZ_CMESH_3D) { dim = 3; nNod = mesh.m3->res.nod.numEnt; nElm = mesh.m3->res.elm.numEnt; maxNod = mesh.m3->res.nod.maxEnt; maxElm = mesh.m3->res.elm.maxEnt; } else { errNum = WLZ_ERR_DOMAIN_TYPE; } break; default: errNum = WLZ_ERR_OBJECT_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { if((nodTbl = (int *)AlcMalloc(maxNod * sizeof(int))) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } /* Output comment identifying the file followed by the number of nodes, * dimension, the number of attributes and the number of boundary markers. * On following records output the node psoitions. */ if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "#%s\n%d %d %d %d\n", nodeFileName, nNod, dim, 0, 1) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } /* Output node positions while building a node table to avoid deleted * nodes. */ if(errNum == WLZ_ERR_NONE) { cnt = 0; if(dim == 2) { for(idN = 0; idN < maxNod; ++idN) { nod2[0] = (WlzCMeshNod2D *)AlcVectorItemGet(mesh.m2->res.nod.vec, idN); if(nod2[0]->idx >= 0) { nodTbl[idN] = cnt++; if(fprintf(fP, "%d %lg %lg %d\n", cnt, nod2[0]->pos.vtX, nod2[0]->pos.vtY, bnd) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } else /* dim == 3 */ { for(idN = 0; idN < maxNod; ++idN) { nod3[0] = (WlzCMeshNod3D *)AlcVectorItemGet(mesh.m3->res.nod.vec, idN); if(nod3[0]->idx >= 0) { nodTbl[idN] = cnt++; if(fprintf(fP, "%d %lg %lg %lg %d\n", cnt, nod3[0]->pos.vtX, nod3[0]->pos.vtY, nod3[0]->pos.vtZ, bnd) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } } /* Close the node file. */ if(fP) { (void )fclose(fP); fP = NULL; } /* Open the element file. */ if(errNum == WLZ_ERR_NONE) { if((eleFileName == NULL) || (*eleFileName == '\0') || ((fP = fopen(eleFileName, "w")) == NULL)) { errNum = WLZ_ERR_READ_EOF; } #ifdef _WIN32 if(fP != NULL) { if(_setmode(_fileno(fP), 0x8000) == -1) { errNum = WLZ_ERR_READ_EOF; } } #endif } /* Output comment identifying the file followed by the number of elements, * # the number of nodes per element and the number of attributes. */ if(errNum == WLZ_ERR_NONE) { if(fprintf(fP, "#%s\n%d %d %d\n", eleFileName, nElm, dim + 1, 0) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; } } /* Output the node indices for each element. */ if(errNum == WLZ_ERR_NONE) { cnt = 0; if(dim == 2) { for(idE = 0; idE < maxElm; ++idE) { elm2 = (WlzCMeshElm2D *)AlcVectorItemGet(mesh.m2->res.elm.vec, idE); if(elm2->idx >= 0) { nod2[0] = WLZ_CMESH_ELM2D_GET_NODE_0(elm2); nod2[1] = WLZ_CMESH_ELM2D_GET_NODE_1(elm2); nod2[2] = WLZ_CMESH_ELM2D_GET_NODE_2(elm2); if(fprintf(fP, "%d %d %d %d\n", ++cnt, nodTbl[nod2[0]->idx] + 1, nodTbl[nod2[1]->idx] + 1, nodTbl[nod2[2]->idx] + 1) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } else /* dim == 3 */ { for(idE = 0; idE < maxElm; ++idE) { elm3 = (WlzCMeshElm3D *)AlcVectorItemGet(mesh.m3->res.elm.vec, idE); if(elm3->idx >= 0) { nod3[0] = WLZ_CMESH_ELM3D_GET_NODE_0(elm3); nod3[1] = WLZ_CMESH_ELM3D_GET_NODE_1(elm3); nod3[2] = WLZ_CMESH_ELM3D_GET_NODE_2(elm3); nod3[3] = WLZ_CMESH_ELM3D_GET_NODE_3(elm3); if(fprintf(fP, "%d %d %d %d %d\n", ++cnt, nodTbl[nod3[0]->idx] + 1, nodTbl[nod3[1]->idx] + 1, nodTbl[nod3[2]->idx] + 1, nodTbl[nod3[3]->idx] + 1) <= 0) { errNum = WLZ_ERR_WRITE_INCOMPLETE; break; } } } } } /* Close the element file. */ if(fP) { (void )fclose(fP); fP = NULL; } AlcFree(nodTbl); return(errNum); }
/*! * \return Object read from file. * \ingroup WlzExtFF * \brief Reads a Woolz object from a pair of files using the node/ele * format. The given file name is used to generate the '.node' * and '.ele' filenames. * \param gvnFileName Given file name. * \param dstErr Destination error number ptr, may be * NULL. */ WlzObject *WlzEffReadObjNodeEle(const char *gvnFileName, WlzErrorNum *dstErr) { int cnt, idx, idE, idN, bnd = 0, dim = 0, nAtr = 0, nBnd = 0, nElm = 0, nNod = 0, nodPerElm = 0; FILE *fP = NULL; char *fileName = NULL, *nodeFileName = NULL, *eleFileName = NULL, *str; int eBuf[4]; WlzVertexP vBuf; WlzCMeshP mesh; WlzObject *obj = NULL; WlzDomain dom; WlzValues val; WlzErrorNum errNum = WLZ_ERR_NONE; char cBuf[256]; WlzCMeshNod2D *nBuf2[4]; WlzCMeshNod3D *nBuf3[4]; vBuf.v = NULL; mesh.v = NULL; dom.core = NULL; val.core = NULL; if((gvnFileName == NULL) || (*gvnFileName == '\0')) { errNum = WLZ_ERR_PARAM_NULL; } else { errNum = WlzEffNodeEleFileNames(&fileName, &nodeFileName, &eleFileName, gvnFileName); } if(errNum == WLZ_ERR_NONE) { if((nodeFileName == NULL) || (*nodeFileName == '\0') || ((fP = fopen(nodeFileName, "r")) == NULL)) { errNum = WLZ_ERR_READ_EOF; } #ifdef _WIN32 if(fP != NULL) { if(_setmode(_fileno(fP), 0x8000) == -1) { errNum = WLZ_ERR_READ_EOF; } } #endif } if(fP == NULL) { errNum = WLZ_ERR_PARAM_NULL; } else { /* Optional records may be comments starting with a '#' but apart * from these the first line should have four integers specifying * the number of nodes, the dimension, the number of attributes * and the number of boundary markers. */ cnt = 0; do { if((str = WlzEffReadObjNodeEleRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; } else if(*str != '#') { if((cnt = sscanf(str, "%d %d %d %d", &nNod, &dim, &nAtr, &nBnd)) != 4) { errNum = WLZ_ERR_READ_INCOMPLETE; } } } while((errNum == WLZ_ERR_NONE) && (cnt != 4)); } /* Check for reasonable number of nodes, etc.... */ if(errNum == WLZ_ERR_NONE) { if((nNod <= 0) || ((dim != 2) && (dim != 3)) || (nAtr != 0) || (nBnd != 1)) { errNum = WLZ_ERR_READ_INCOMPLETE; } } if(errNum == WLZ_ERR_NONE) { idN = 0; if(dim == 2) { /* Create a new 2D constrained mesh. */ mesh.m2 = WlzCMeshNew2D(&errNum); /* Read in the node positions into a temporary buffer computing their * bounding box and then create the nodes. */ if(errNum == WLZ_ERR_NONE) { if((vBuf.v = AlcMalloc(sizeof(WlzDVertex2) * nNod)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } while((errNum == WLZ_ERR_NONE) && (idN < nNod)) { if((str = WlzEffReadObjNodeEleRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else if(*str != '#') { if((sscanf(str, "%d %lg %lg %d", &idx, &(vBuf.d2[idN].vtX), &(vBuf.d2[idN].vtY), &bnd) == 4) && (idx = idN + 1)) { if(idN == 0) { mesh.m2->bBox.xMin = mesh.m2->bBox.xMax = vBuf.d2[idN].vtX; mesh.m2->bBox.yMin = mesh.m2->bBox.yMax = vBuf.d2[idN].vtY; } else { if(vBuf.d2[idN].vtX < mesh.m2->bBox.xMin) { mesh.m2->bBox.xMin = vBuf.d2[idN].vtX; } else if(vBuf.d2[idN].vtX > mesh.m2->bBox.xMax) { mesh.m2->bBox.xMax = vBuf.d2[idN].vtX; } if(vBuf.d2[idN].vtY < mesh.m2->bBox.yMin) { mesh.m2->bBox.yMin = vBuf.d2[idN].vtY; } else if(vBuf.d2[idN].vtY > mesh.m2->bBox.yMax) { mesh.m2->bBox.yMax = vBuf.d2[idN].vtY; } } ++idN; } else { errNum = WLZ_ERR_READ_INCOMPLETE; break; } } } /* Create the nodes. */ if(errNum == WLZ_ERR_NONE) { if(AlcVectorExtendAndGet(mesh.m2->res.nod.vec, nNod) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { errNum = WlzCMeshReassignGridCells2D(mesh.m2, nNod); } } if(errNum == WLZ_ERR_NONE) { for(idN = 0; idN < nNod; ++idN) { nBuf2[0] = WlzCMeshNewNod2D(mesh.m2, vBuf.d2[idN], NULL); nBuf2[0]->pos = vBuf.d2[idN]; nBuf2[0]->flags = 0; } } } else /* dim == 3 */ { /* Create a new 3D constrained mesh. */ mesh.m3 = WlzCMeshNew3D(&errNum); /* Read in the node positions into a temporary buffer computing their * bounding box and then create the nodes. */ if(errNum == WLZ_ERR_NONE) { if((vBuf.v = AlcMalloc(sizeof(WlzDVertex3) * nNod)) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } } while((errNum == WLZ_ERR_NONE) && (idN < nNod)) { if((str = WlzEffReadObjNodeEleRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else if(*str != '#') { if((sscanf(str, "%d %lg %lg %lg %d", &idx, &(vBuf.d3[idN].vtX), &(vBuf.d3[idN].vtY), &(vBuf.d3[idN].vtZ), &bnd) == 5) && (idx = idN + 1)) { if(idN == 0) { mesh.m3->bBox.xMin = mesh.m3->bBox.xMax = vBuf.d3[idN].vtX; mesh.m3->bBox.yMin = mesh.m3->bBox.yMax = vBuf.d3[idN].vtY; mesh.m3->bBox.zMin = mesh.m3->bBox.zMax = vBuf.d3[idN].vtZ; } else { if(vBuf.d3[idN].vtX < mesh.m3->bBox.xMin) { mesh.m3->bBox.xMin = vBuf.d3[idN].vtX; } else if(vBuf.d3[idN].vtX > mesh.m3->bBox.xMax) { mesh.m3->bBox.xMax = vBuf.d3[idN].vtX; } if(vBuf.d3[idN].vtY < mesh.m3->bBox.yMin) { mesh.m3->bBox.yMin = vBuf.d3[idN].vtY; } else if(vBuf.d3[idN].vtY > mesh.m3->bBox.yMax) { mesh.m3->bBox.yMax = vBuf.d3[idN].vtY; } if(vBuf.d3[idN].vtZ < mesh.m3->bBox.zMin) { mesh.m3->bBox.zMin = vBuf.d3[idN].vtZ; } else if(vBuf.d3[idN].vtZ > mesh.m3->bBox.zMax) { mesh.m3->bBox.zMax = vBuf.d3[idN].vtZ; } } ++idN; } else { errNum = WLZ_ERR_READ_INCOMPLETE; break; } } } /* Create the nodes. */ if(errNum == WLZ_ERR_NONE) { if(AlcVectorExtendAndGet(mesh.m3->res.nod.vec, nNod) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } else { errNum = WlzCMeshReassignGridCells3D(mesh.m3, nNod); } } if(errNum == WLZ_ERR_NONE) { for(idN = 0; idN < nNod; ++idN) { nBuf3[0] = WlzCMeshNewNod3D(mesh.m3, vBuf.d3[idN], NULL); nBuf3[0]->pos = vBuf.d3[idN]; nBuf3[0]->flags = 0; } } } } AlcFree(vBuf.v); /* Close node file. */ if(fP) { (void )fclose(fP); fP = NULL; } /* Read in the elements from the .ele file and create them. */ if(errNum == WLZ_ERR_NONE) { if((eleFileName == NULL) || (*eleFileName == '\0') || ((fP = fopen(eleFileName, "r")) == NULL)) { errNum = WLZ_ERR_READ_EOF; } #ifdef _WIN32 if(fP != NULL) { if(_setmode(_fileno(fP), 0x8000) == -1) { errNum = WLZ_ERR_READ_EOF; } } #endif } if(errNum == WLZ_ERR_NONE) { /* Optional records may be comments starting with a '#' but apart * from these the first line should have four integers specifying * the number of nodes, the dimension, the number of attributes * and the number of boundary markers. */ cnt = 0; do { if((str = WlzEffReadObjNodeEleRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; } else if(*str != '#') { if((cnt = sscanf(str, "%d %d %d", &nElm, &nodPerElm, &nAtr)) != 3) { errNum = WLZ_ERR_READ_INCOMPLETE; } } } while((errNum == WLZ_ERR_NONE) && (cnt != 3)); } /* Check for reasonable number of nodes, etc.... */ if(errNum == WLZ_ERR_NONE) { if((nElm <= 0) || (nodPerElm != dim + 1) || (nAtr != 0)) { errNum = WLZ_ERR_READ_INCOMPLETE; } } if(errNum == WLZ_ERR_NONE) { idE = 0; if(dim == 2) { if(AlcVectorExtendAndGet(mesh.m2->res.elm.vec, nElm) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } while((errNum == WLZ_ERR_NONE) && (idE < nElm)) { if((str = WlzEffReadObjNodeEleRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else if(*str != '#') { if(sscanf(str, "%d %d %d %d", &idx, eBuf + 0, eBuf + 1, eBuf + 2) == 4) { if((idx != idE + 1) || (eBuf[0] <= 0) || (eBuf[0] > nNod) || (eBuf[1] <= 0) || (eBuf[1] > nNod) || (eBuf[2] <= 0) || (eBuf[2] > nNod)) { errNum = WLZ_ERR_MEM_ALLOC; break; } for(idN = 0; idN < 4; ++idN) { nBuf2[idN] = (WlzCMeshNod2D *) AlcVectorItemGet(mesh.m2->res.nod.vec, eBuf[idN] - 1); } (void )WlzCMeshNewElm2D(mesh.m2, nBuf2[0], nBuf2[2], nBuf2[1], 1, &errNum); ++idE; } else { errNum = WLZ_ERR_READ_INCOMPLETE; break; } } } if(errNum == WLZ_ERR_NONE) { WlzCMeshUpdateMaxSqEdgLen2D(mesh.m2); dom.cm2 = mesh.m2; obj = WlzMakeMain(WLZ_CMESH_2D, dom, val, NULL, NULL, &errNum); } } else /* dim == 3 */ { if(AlcVectorExtendAndGet(mesh.m3->res.elm.vec, nElm) == NULL) { errNum = WLZ_ERR_MEM_ALLOC; } while((errNum == WLZ_ERR_NONE) && (idE < nElm)) { if((str = WlzEffReadObjNodeEleRec(fP, cBuf, 256)) == NULL) { errNum = WLZ_ERR_READ_INCOMPLETE; break; } else if(*str != '#') { if(sscanf(str, "%d %d %d %d %d", &idx, eBuf + 0, eBuf + 1, eBuf + 2, eBuf + 3) == 5) { if((eBuf[0] <= 0) || (eBuf[0] > nNod) || (eBuf[1] <= 0) || (eBuf[1] > nNod) || (eBuf[2] <= 0) || (eBuf[2] > nNod) || (eBuf[3] <= 0) || (eBuf[3] > nNod)) { errNum = WLZ_ERR_MEM_ALLOC; break; } for(idN = 0; idN < 4; ++idN) { nBuf3[idN] = (WlzCMeshNod3D *) AlcVectorItemGet(mesh.m3->res.nod.vec, eBuf[idN] - 1); } (void )WlzCMeshNewElm3D(mesh.m3, nBuf3[0], nBuf3[1], nBuf3[3], nBuf3[2], 1, &errNum); ++idE; } else { errNum = WLZ_ERR_READ_INCOMPLETE; break; } } } if(errNum == WLZ_ERR_NONE) { WlzCMeshUpdateMaxSqEdgLen3D(mesh.m3); dom.cm3 = mesh.m3; obj = WlzMakeMain(WLZ_CMESH_3D, dom, val, NULL, NULL, &errNum); } } } /* Close element file. */ if(fP) { (void )fclose(fP); } if(errNum != WLZ_ERR_NONE) { if(dim == 2) { (void )WlzCMeshFree2D(mesh.m2); } else if(dim == 3) { (void )WlzCMeshFree3D(mesh.m3); } } if(dstErr) { *dstErr = errNum; } return(obj); }
int main(int argc, char *argv[]) { int idN, idM, nSeeds, nBndSeeds, boundFlg = 0, imgFlg = 0, interp = 0, seedFlg = 0, ok = 1, option, usage = 0; size_t vtxSize = sizeof(WlzDVertex2); WlzObjectType outObjType; WlzVertexType bndVtxType; WlzVertex seed; WlzVertexP bndSeeds, seeds; FILE *fP = NULL; char *outObjFileStr, *refObjFileStr = NULL, *meshFileStr; const char *errMsgStr; WlzErrorNum errNum = WLZ_ERR_NONE; WlzObject *outObj = NULL, *mshObj = NULL, *refObj = NULL; WlzCMeshP mesh; WlzCMeshNodP nod; static char optList[] = "bhiLo:r:s:"; const char meshFileStrDef[] = "-", outObjFileStrDef[] = "-"; mesh.v = NULL; opterr = 0; seeds.v = NULL; bndSeeds.v = NULL; outObjFileStr = (char *)outObjFileStrDef; meshFileStr = (char *)meshFileStrDef; seed.d3.vtX = seed.d3.vtY = seed.d3.vtZ = 0.0; while((usage == 0) && ((option = getopt(argc, argv, optList)) != EOF)) { switch(option) { case 'b': boundFlg = 1; break; case 'i': imgFlg = 1; break; case 's': seedFlg = 1; if(sscanf(optarg, "%lg,%lg,%lg", &(seed.d3.vtX), &(seed.d3.vtY), &(seed.d3.vtZ)) < 1) { usage = 1; } break; case 'o': outObjFileStr = optarg; break; case 'r': refObjFileStr = optarg; break; case 'L': interp = 1; break; case 'h': /* FALLTHROUGH */ default: usage = 1; break; } } ok = usage == 0; if(ok) { if((meshFileStr == NULL) || (*meshFileStr == '\0') || (outObjFileStr == NULL) || (*outObjFileStr == '\0')) { ok = 0; usage = 1; } if(ok && (optind < argc)) { if((optind + 1) != argc) { usage = 1; ok = 0; } else { meshFileStr = *(argv + optind); } } } if(ok && refObjFileStr) { if(((fP = (strcmp(refObjFileStr, "-")? fopen(refObjFileStr, "r"): stdin)) == NULL) || ((refObj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL) || (errNum != WLZ_ERR_NONE)) { ok = 0; (void )fprintf(stderr, "%s: failed to read reference object from file %s\n", *argv, refObjFileStr); } if(fP && strcmp(refObjFileStr, "-")) { (void )fclose(fP); fP = NULL; } } if(ok) { if(((fP = (strcmp(meshFileStr, "-")? fopen(meshFileStr, "r"): stdin)) == NULL) || ((mshObj = WlzAssignObject(WlzReadObj(fP, &errNum), NULL)) == NULL) || (errNum != WLZ_ERR_NONE)) { ok = 0; (void )fprintf(stderr, "%s: failed to read mesh object from file %s\n", *argv, meshFileStr); } if(fP && strcmp(meshFileStr, "-")) { (void )fclose(fP); fP = NULL; } } if(ok) { switch(mshObj->type) { case WLZ_CMESH_2D: mesh.m2 = mshObj->domain.cm2; break; case WLZ_CMESH_3D: mesh.m3 = mshObj->domain.cm3; break; default: ok = 0; errNum = WLZ_ERR_OBJECT_TYPE; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Invalid mesh object, must be WLZ_CMESH_[23]D (%s),\n", argv[0], errMsgStr); break; } } if(ok && mshObj) { switch(mshObj->type) { case WLZ_CMESH_2D: vtxSize = sizeof(WlzDVertex2); if((refObj != NULL) && (refObj->type != WLZ_2D_DOMAINOBJ)) { ok = 0; } break; case WLZ_CMESH_3D: vtxSize = sizeof(WlzDVertex3); if((refObj != NULL) && (refObj->type != WLZ_3D_DOMAINOBJ)) { ok = 0; } break; default: ok = 0; } if(ok == 0) { errNum = WLZ_ERR_OBJECT_TYPE; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Mesh and reference objects must have the same\n" "dimension (%s)\n", argv[0], errMsgStr); } } /* Create seed buffer. */ if(ok) { nSeeds = (seedFlg != 0); if(boundFlg) { nSeeds += WlzCMeshSetBoundNodFlags(mesh); } if(refObj) { bndSeeds = WlzVerticesFromObjBnd(refObj, &nBndSeeds, &bndVtxType, &errNum); nSeeds += nBndSeeds; } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to extract seeds (%s)\n", argv[0], errMsgStr); } else if(nSeeds < 1) { ok = 0; (void )fprintf(stderr, "%s: Number of seeds must be > 0.\n", argv[0]); } } if(ok) { if((seeds.v = AlcMalloc(vtxSize * nSeeds)) == NULL) { ok = 0; errNum = WLZ_ERR_MEM_ALLOC; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to allocate seed buffer (%s)\n", argv[0], errMsgStr); } } if(ok) { switch(mshObj->type) { case WLZ_CMESH_2D: idN = 0; outObjType = (imgFlg != 0)? WLZ_2D_DOMAINOBJ: WLZ_CMESH_2D; if(seedFlg) { idN = 1; seeds.d2->vtX = seed.d2.vtX; seeds.d2->vtY = seed.d2.vtY; } if(boundFlg) { for(idM = 0; idM < mesh.m2->res.nod.maxEnt; ++idM) { nod.n2 = (WlzCMeshNod2D *) AlcVectorItemGet(mesh.m2->res.nod.vec, idM); if((nod.n2->idx >= 0) && ((nod.n2->flags & WLZ_CMESH_NOD_FLAG_BOUNDARY) != 0)) { seeds.d2[idN++] = nod.n2->pos; } } } if(refObj) { switch(bndVtxType) { case WLZ_VERTEX_I2: WlzValueCopyIVertexToDVertex(seeds.d2 + idN, bndSeeds.i2, nBndSeeds); break; case WLZ_VERTEX_F2: WlzValueCopyFVertexToDVertex(seeds.d2 + idN, bndSeeds.f2, nBndSeeds); break; case WLZ_VERTEX_D2: WlzValueCopyDVertexToDVertex(seeds.d2 + idN, bndSeeds.d2, nBndSeeds); break; default: errNum = WLZ_ERR_PARAM_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { outObj = WlzCMeshDistance2D(mshObj, outObjType, nSeeds, seeds.d2, (interp)? WLZ_INTERPOLATION_KRIG: WLZ_INTERPOLATION_BARYCENTRIC, &errNum); } break; case WLZ_CMESH_3D: idN = 0; outObjType = (imgFlg != 0)? WLZ_3D_DOMAINOBJ: WLZ_CMESH_3D; if(seedFlg) { idN = 1; seeds.d3->vtX = seed.d3.vtX; seeds.d3->vtY = seed.d3.vtY; seeds.d3->vtZ = seed.d3.vtZ; } if(boundFlg) { for(idM = 0; idM < mesh.m3->res.nod.maxEnt; ++idM) { nod.n3 = (WlzCMeshNod3D *) AlcVectorItemGet(mesh.m3->res.nod.vec, idM); if((nod.n3->idx >= 0) && ((nod.n3->flags & WLZ_CMESH_NOD_FLAG_BOUNDARY) != 0)) { seeds.d3[idN++] = nod.n3->pos; } } } if(refObj) { switch(bndVtxType) { case WLZ_VERTEX_I3: WlzValueCopyIVertexToDVertex3(seeds.d3 + idN, bndSeeds.i3, nBndSeeds); break; case WLZ_VERTEX_F3: WlzValueCopyFVertexToDVertex3(seeds.d3 + idN, bndSeeds.f3, nBndSeeds); break; case WLZ_VERTEX_D3: WlzValueCopyDVertexToDVertex3(seeds.d3 + idN, bndSeeds.d3, nBndSeeds); break; default: errNum = WLZ_ERR_PARAM_TYPE; break; } } if(errNum == WLZ_ERR_NONE) { outObj = WlzCMeshDistance3D(mshObj, outObjType, nSeeds, seeds.d3, (interp)? WLZ_INTERPOLATION_KRIG: WLZ_INTERPOLATION_BARYCENTRIC, &errNum); } break; break; default: break; } if(errNum != WLZ_ERR_NONE) { ok = 0; (void )WlzStringFromErrorNum(errNum, &errMsgStr); (void )fprintf(stderr, "%s: Failed to create domain object with distances (%s)\n", argv[0], errMsgStr); } } AlcFree(seeds.v); AlcFree(bndSeeds.v); WlzFreeObj(refObj); WlzFreeObj(mshObj); if(ok) { errNum = WLZ_ERR_WRITE_EOF; if(((fP = (strcmp(outObjFileStr, "-")? fopen(outObjFileStr, "w"): stdout)) == NULL) || ((errNum = WlzWriteObj(fP, outObj)) != WLZ_ERR_NONE)) { ok = 0; (void )fprintf(stderr, "%s: failed to write output object to file %s\n", *argv, outObjFileStr); } if(fP && strcmp(outObjFileStr, "-")) { (void )fclose(fP); fP = NULL; } } (void )WlzFreeObj(outObj); if(usage) { fprintf(stderr, "Usage: %s [-b] [-h] [-o<out obj file>] [-r<ref obj file>]\n" " [-L] [-s #,#,#] [<input mesh file>]\n" "Constructs a 2D or 3D domain object the values of which are\n" "the minimum distance from the given seeds points in the given\n" "conforming mesh. The domain of the output object covers the\n" "input mesh.\n" "Version: %s\n" "Options:\n" " -h Help, prints this usage message.\n" " -i Output an image (ie a 2 or 3D domain object) with\n" " interpolated distance values rather than a mesh with\n" " indexed values.\n" " -L Use expensive interpolation (mainly useful as a test).\n" " -o Output object.\n" " -b Set seed points around the boundary of the mesh.\n" " -s Single seed position.\n" " -r Reference object with seed points around it's boundary.\n", argv[0], WlzVersion()); } return(!ok); }