// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int32_t AbaqusSurfaceMeshWriter::writeTriangles(FILE* f) { int32_t err = 0; TriangleGeom::Pointer triangleGeom = getDataContainerArray()->getDataContainer(getSurfaceMeshFaceLabelsArrayPath().getDataContainerName())->getGeometryAs<TriangleGeom>(); int64_t numTri = triangleGeom->getNumberOfTris(); int64_t* triangles = triangleGeom->getTriPointer(0); fprintf(f, "*ELEMENT, TYPE=%s\n", TRI_ELEMENT_TYPE); for (int64_t i = 1; i <= numTri; ++i) { // When we get the node index, add 1 to it because Abaqus number is 1 based. int64_t nId0 = triangles[(i - 1) * 3] + 1; int64_t nId1 = triangles[(i - 1) * 3 + 1] + 1; int64_t nId2 = triangles[(i - 1) * 3 + 2] + 1; fprintf(f, "%lld, %lld, %lld, %lld\n", (long long int)i, (long long int)nId0, (long long int)nId1, (long long int)nId2); } return err; }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void SurfaceMeshToNonconformalVtk::execute() { int err = 0; setErrorCondition(err); dataCheck(); if(getErrorCondition() < 0) { return; } DataContainer::Pointer m = getDataContainerArray()->getDataContainer(m_SurfaceMeshFaceLabelsArrayPath.getDataContainerName()); TriangleGeom::Pointer triangleGeom = getDataContainerArray()->getDataContainer(getSurfaceMeshFaceLabelsArrayPath().getDataContainerName())->getGeometryAs<TriangleGeom>(); float* nodes = triangleGeom->getVertexPointer(0); int64_t* triangles = triangleGeom->getTriPointer(0); qint64 numNodes = triangleGeom->getNumberOfVertices(); int64_t numTriangles = triangleGeom->getNumberOfTris(); // Make sure any directory path is also available as the user may have just typed // in a path without actually creating the full path QFileInfo fi(getOutputVtkFile()); QDir parentPath = fi.path(); if(!parentPath.mkpath(".")) { QString ss = QObject::tr("Error creating parent path '%1'").arg(parentPath.absolutePath()); setErrorCondition(-1); notifyErrorMessage(getHumanLabel(), ss, getErrorCondition()); return; } // Open the output VTK File for writing FILE* vtkFile = NULL; vtkFile = fopen(getOutputVtkFile().toLatin1().data(), "wb"); if (NULL == vtkFile) { QString ss = QObject::tr("Error creating file '%1'").arg(getOutputVtkFile()); setErrorCondition(-18542); notifyErrorMessage(getHumanLabel(), ss, getErrorCondition()); return; } ScopedFileMonitor vtkFileMonitor(vtkFile); notifyStatusMessage(getHumanLabel(), "Writing Vertex Data ...."); fprintf(vtkFile, "# vtk DataFile Version 2.0\n"); fprintf(vtkFile, "Data set from DREAM.3D Surface Meshing Module\n"); if (m_WriteBinaryFile) { fprintf(vtkFile, "BINARY\n"); } else { fprintf(vtkFile, "ASCII\n"); } fprintf(vtkFile, "DATASET POLYDATA\n"); int numberWrittenNodes = 0; for (int i = 0; i < numNodes; i++) { // Node& n = nodes[i]; // Get the current Node if (m_SurfaceMeshNodeType[i] > 0) { ++numberWrittenNodes; } else { qDebug() << "Node Type Invalid: " << i << "::" << (int)(m_SurfaceMeshNodeType[i]) ;} } fprintf(vtkFile, "POINTS %d float\n", numberWrittenNodes); float pos[3] = {0.0f, 0.0f, 0.0f}; size_t totalWritten = 0; // Write the POINTS data (Vertex) for (int i = 0; i < numNodes; i++) { if (m_SurfaceMeshNodeType[i] > 0) { pos[0] = static_cast<float>(nodes[i * 3]); pos[1] = static_cast<float>(nodes[i * 3 + 1]); pos[2] = static_cast<float>(nodes[i * 3 + 2]); if (m_WriteBinaryFile == true) { SIMPLib::Endian::FromSystemToBig::convert(pos[0]); SIMPLib::Endian::FromSystemToBig::convert(pos[1]); SIMPLib::Endian::FromSystemToBig::convert(pos[2]); totalWritten = fwrite(pos, sizeof(float), 3, vtkFile); if(totalWritten != 3) {} } else { fprintf(vtkFile, "%f %f %f\n", pos[0], pos[1], pos[2]); // Write the positions to the output file } } } // Write the triangle indices into the vtk File notifyStatusMessage(getHumanLabel(), "Writing Faces ...."); int tData[4]; // Store all the unique Spins QMap<int32_t, int32_t> featureTriangleCount; for (int i = 0; i < numTriangles; i++) { if (featureTriangleCount.find(m_SurfaceMeshFaceLabels[i * 2]) == featureTriangleCount.end()) { featureTriangleCount[m_SurfaceMeshFaceLabels[i * 2]] = 1; } else { featureTriangleCount[m_SurfaceMeshFaceLabels[i * 2]]++; } if (featureTriangleCount.find(m_SurfaceMeshFaceLabels[i * 2 + 1]) == featureTriangleCount.end()) { featureTriangleCount[m_SurfaceMeshFaceLabels[i * 2 + 1]] = 1; } else { featureTriangleCount[m_SurfaceMeshFaceLabels[i * 2 + 1]]++; } } // Write the POLYGONS fprintf(vtkFile, "\nPOLYGONS %lld %lld\n", (long long int)(numTriangles * 2), (long long int)(numTriangles * 2 * 4)); size_t totalCells = 0; // Loop over all the features for(QMap<int32_t, int32_t>::iterator featureIter = featureTriangleCount.begin(); featureIter != featureTriangleCount.end(); ++featureIter) { totalCells += featureIter.value(); } Q_ASSERT(totalCells == (size_t)(numTriangles * 2) ); // Loop over all the features for(QMap<int32_t, int32_t>::iterator featureIter = featureTriangleCount.begin(); featureIter != featureTriangleCount.end(); ++featureIter) { int32_t gid = featureIter.key(); // The current Feature Id int32_t numTriToWrite = featureIter.value(); // The number of triangles for this feature uint8_t doWrite = 0; // Loop over all the triangles looking for the current feature id // this is probably sub-optimal as if we have 1000 features we are going to loop 1000 times but this will use the // least amount of memory. We could run a filter to group the triangles by feature but then we would need an // additional amount of memory equal to 3X the memory used for the triangle list because every triangle will be listed // twice. We could get some slightly better performance if we buffered 4K worth of data then wrote out that data // in one chunk versus what we are doing here. for (int j = 0; j < numTriangles; j++) { doWrite = 0; if (m_SurfaceMeshFaceLabels[j * 2] == gid ) { doWrite = 1; } else if (m_SurfaceMeshFaceLabels[j * 2 + 1] == gid) { doWrite = 2; } // We need to flip the winding of the triangle if (doWrite == 0) { continue; } // Labels in the triangle did match the current feature id. if (doWrite == 1) { tData[0] = 3; // Push on the total number of entries for this entry tData[1] = triangles[j * 3]; tData[2] = triangles[j * 3 + 1]; tData[3] = triangles[j * 3 + 2]; } else { tData[0] = 3; // Push on the total number of entries for this entry tData[1] = triangles[j * 3 + 2]; tData[2] = triangles[j * 3 + 1]; tData[3] = triangles[j * 3]; } if (m_WriteBinaryFile == true) { SIMPLib::Endian::FromSystemToBig::convert(tData[0]); SIMPLib::Endian::FromSystemToBig::convert(tData[1]); // Index of Vertex 0 SIMPLib::Endian::FromSystemToBig::convert(tData[2]); // Index of Vertex 1 SIMPLib::Endian::FromSystemToBig::convert(tData[3]); // Index of Vertex 2 fwrite(tData, sizeof(int), 4, vtkFile); } else { fprintf(vtkFile, "3 %d %d %d\n", tData[1], tData[2], tData[3]); } numTriToWrite--; } if (numTriToWrite != 0) { qDebug() << "Not enough triangles written: " << gid << "::" << numTriToWrite << " Total Triangles to Write " << featureIter.value(); } } // Write the POINT_DATA section err = writePointData(vtkFile); // Write the CELL_DATA section err = writeCellData(vtkFile, featureTriangleCount); fprintf(vtkFile, "\n"); setErrorCondition(0); notifyStatusMessage(getHumanLabel(), "Complete"); }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void SurfaceMeshToVtk::execute() { int err = 0; setErrorCondition(err); dataCheck(); if(getErrorCondition() < 0) { return; } setErrorCondition(0); DataContainer::Pointer sm = getDataContainerArray()->getDataContainer(m_SurfaceMeshFaceLabelsArrayPath.getDataContainerName()); /* Place all your code to execute your filter here. */ TriangleGeom::Pointer triangleGeom = getDataContainerArray()->getDataContainer(getSurfaceMeshFaceLabelsArrayPath().getDataContainerName())->getGeometryAs<TriangleGeom>(); float* nodes = triangleGeom->getVertexPointer(0); int64_t* triangles = triangleGeom->getTriPointer(0); qint64 numNodes = triangleGeom->getNumberOfVertices(); int64_t numTriangles = triangleGeom->getNumberOfTris(); // Make sure any directory path is also available as the user may have just typed // in a path without actually creating the full path QFileInfo fi(getOutputVtkFile()); QDir parentPath = fi.path(); if(!parentPath.mkpath(".")) { QString ss = QObject::tr("Error creating parent path '%1'").arg(parentPath.absolutePath()); notifyErrorMessage(getHumanLabel(), ss, -1); setErrorCondition(-1); return; } // Open the output VTK File for writing FILE* vtkFile = NULL; vtkFile = fopen(getOutputVtkFile().toLatin1().data(), "wb"); if (NULL == vtkFile) { QString ss = QObject::tr("Error creating file '%1'").arg(getOutputVtkFile()); notifyErrorMessage(getHumanLabel(), ss, -18542); setErrorCondition(-18542); return; } ScopedFileMonitor vtkFileMonitor(vtkFile); fprintf(vtkFile, "# vtk DataFile Version 2.0\n"); fprintf(vtkFile, "Data set from DREAM.3D Surface Meshing Module\n"); if (m_WriteBinaryFile) { fprintf(vtkFile, "BINARY\n"); } else { fprintf(vtkFile, "ASCII\n"); } fprintf(vtkFile, "DATASET POLYDATA\n"); int numberWrittenumNodes = 0; for (int i = 0; i < numNodes; i++) { // Node& n = nodes[i]; // Get the current Node if (m_SurfaceMeshNodeType[i] > 0) { ++numberWrittenumNodes; } } fprintf(vtkFile, "POINTS %d float\n", numberWrittenumNodes); float pos[3] = {0.0f, 0.0f, 0.0f}; size_t totalWritten = 0; // Write the POINTS data (Vertex) for (int i = 0; i < numNodes; i++) { if (m_SurfaceMeshNodeType[i] > 0) { pos[0] = static_cast<float>(nodes[i * 3]); pos[1] = static_cast<float>(nodes[i * 3 + 1]); pos[2] = static_cast<float>(nodes[i * 3 + 2]); if (m_WriteBinaryFile == true) { SIMPLib::Endian::FromSystemToBig::convert(pos[0]); SIMPLib::Endian::FromSystemToBig::convert(pos[1]); SIMPLib::Endian::FromSystemToBig::convert(pos[2]); totalWritten = fwrite(pos, sizeof(float), 3, vtkFile); if (totalWritten != sizeof(float) * 3) { } } else { fprintf(vtkFile, "%f %f %f\n", pos[0], pos[1], pos[2]); // Write the positions to the output file } } } int tData[4]; int triangleCount = numTriangles; // int tn1, tn2, tn3; if (false == m_WriteConformalMesh) { triangleCount = numTriangles * 2; } // Write the POLYGONS fprintf(vtkFile, "\nPOLYGONS %d %d\n", triangleCount, (triangleCount * 4)); for (int j = 0; j < numTriangles; j++) { // Triangle& t = triangles[j]; tData[1] = triangles[j * 3]; tData[2] = triangles[j * 3 + 1]; tData[3] = triangles[j * 3 + 2]; if (m_WriteBinaryFile == true) { tData[0] = 3; // Push on the total number of entries for this entry SIMPLib::Endian::FromSystemToBig::convert(tData[0]); SIMPLib::Endian::FromSystemToBig::convert(tData[1]); // Index of Vertex 0 SIMPLib::Endian::FromSystemToBig::convert(tData[2]); // Index of Vertex 1 SIMPLib::Endian::FromSystemToBig::convert(tData[3]); // Index of Vertex 2 fwrite(tData, sizeof(int), 4, vtkFile); if (false == m_WriteConformalMesh) { tData[0] = tData[1]; tData[1] = tData[3]; tData[3] = tData[0]; tData[0] = 3; SIMPLib::Endian::FromSystemToBig::convert(tData[0]); fwrite(tData, sizeof(int), 4, vtkFile); } } else { fprintf(vtkFile, "3 %d %d %d\n", tData[1], tData[2], tData[3]); if (false == m_WriteConformalMesh) { fprintf(vtkFile, "3 %d %d %d\n", tData[3], tData[2], tData[1]); } } } // Write the POINT_DATA section err = writePointData(vtkFile); // Write the CELL_DATA section err = writeCellData(vtkFile); fprintf(vtkFile, "\n"); setErrorCondition(0); notifyStatusMessage(getHumanLabel(), "Complete"); }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void ReadStlFile::eliminate_duplicate_nodes() { DataContainer::Pointer sm = getDataContainerArray()->getDataContainer(m_SurfaceMeshDataContainerName); TriangleGeom::Pointer triangleGeom = sm->getGeometryAs<TriangleGeom>(); float* vertex = triangleGeom->getVertexPointer(0); int64_t nNodes = triangleGeom->getNumberOfVertices(); int64_t* triangles = triangleGeom->getTriPointer(0); int64_t nTriangles = triangleGeom->getNumberOfTris(); float stepX = (m_maxXcoord - m_minXcoord) / 100.0f; float stepY = (m_maxYcoord - m_minYcoord) / 100.0f; float stepZ = (m_maxZcoord - m_minZcoord) / 100.0f; QVector<QVector<size_t> > nodesInBin(100 * 100 * 100); // determine (xyz) bin each node falls in - used to speed up node comparison int32_t bin = 0, xBin = 0, yBin = 0, zBin = 0; for (int64_t i = 0; i < nNodes; i++) { xBin = (vertex[i * 3] - m_minXcoord) / stepX; yBin = (vertex[i * 3 + 1] - m_minYcoord) / stepY; zBin = (vertex[i * 3 + 2] - m_minZcoord) / stepZ; if (xBin == 100) { xBin = 99; } if (yBin == 100) { yBin = 99; } if (zBin == 100) { zBin = 99; } bin = (zBin * 10000) + (yBin * 100) + xBin; nodesInBin[bin].push_back(i); } // Create array to hold unique node numbers Int64ArrayType::Pointer uniqueIdsPtr = Int64ArrayType::CreateArray(nNodes, "uniqueIds"); int64_t* uniqueIds = uniqueIdsPtr->getPointer(0); for (int64_t i = 0; i < nNodes; i++) { uniqueIds[i] = i; } #ifdef SIMPLib_USE_PARALLEL_ALGORITHMS tbb::task_scheduler_init init; bool doParallel = true; #endif //Parallel algorithm to find duplicate nodes #ifdef SIMPLib_USE_PARALLEL_ALGORITHMS if (doParallel == true) { tbb::parallel_for(tbb::blocked_range<size_t>(0, 100 * 100 * 100), FindUniqueIdsImpl(triangleGeom->getVertices(), nodesInBin, uniqueIds), tbb::auto_partitioner()); } else #endif { FindUniqueIdsImpl serial(triangleGeom->getVertices(), nodesInBin, uniqueIds); serial.convert(0, 100 * 100 * 100); } //renumber the unique nodes int64_t uniqueCount = 0; for (int64_t i = 0; i < nNodes; i++) { if(uniqueIds[i] == i) { uniqueIds[i] = uniqueCount; uniqueCount++; } else { uniqueIds[i] = uniqueIds[uniqueIds[i]]; } } // Move nodes to unique Id and then resize nodes array for (int64_t i = 0; i < nNodes; i++) { vertex[uniqueIds[i] * 3] = vertex[i * 3]; vertex[uniqueIds[i] * 3 + 1] = vertex[i * 3 + 1]; vertex[uniqueIds[i] * 3 + 2] = vertex[i * 3 + 2]; } triangleGeom->resizeVertexList(uniqueCount); // Update the triangle nodes to reflect the unique ids int64_t node1 = 0, node2 = 0, node3 = 0; for (int64_t i = 0; i < nTriangles; i++) { node1 = triangles[i * 3]; node2 = triangles[i * 3 + 1]; node3 = triangles[i * 3 + 2]; triangles[i * 3] = uniqueIds[node1]; triangles[i * 3 + 1] = uniqueIds[node2]; triangles[i * 3 + 2] = uniqueIds[node3]; } }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void ReadStlFile::readFile() { DataContainer::Pointer sm = getDataContainerArray()->getDataContainer(m_SurfaceMeshDataContainerName); // Open File FILE* f = fopen(m_StlFilePath.toLatin1().data(), "rb"); if (NULL == f) { setErrorCondition(-1003); notifyErrorMessage(getHumanLabel(), "Error opening STL file", -1003); return; } // Read Header char h[80]; int32_t triCount = 0; fread(h, sizeof(int32_t), 20, f); fread(&triCount, sizeof(int32_t), 1, f); TriangleGeom::Pointer triangleGeom = sm->getGeometryAs<TriangleGeom>(); triangleGeom->resizeTriList(triCount); triangleGeom->resizeVertexList(triCount * 3); float* nodes = triangleGeom->getVertexPointer(0); int64_t* triangles = triangleGeom->getTriPointer(0); // Resize the triangle attribute matrix to hold the normals and update the normals pointer QVector<size_t> tDims(1, triCount); sm->getAttributeMatrix(getFaceAttributeMatrixName())->resizeAttributeArrays(tDims); updateFaceInstancePointers(); // Read the triangles static const size_t k_StlElementCount = 12; float v[k_StlElementCount]; unsigned short attr; for (int32_t t = 0; t < triCount; ++t) { fread(reinterpret_cast<void*>(v), sizeof(float), k_StlElementCount, f); fread(reinterpret_cast<void*>(&attr), sizeof(unsigned short), 1, f); if (attr > 0) { std::vector<unsigned char> buffer(attr); // Allocate a buffer for the STL attribute data to be placed into fread( reinterpret_cast<void*>(&(buffer.front())), attr, 1, f); // Read the bytes into the buffer so that we can skip it. } if(v[3] < m_minXcoord) { m_minXcoord = v[3]; } if(v[3] > m_maxXcoord) { m_maxXcoord = v[3]; } if(v[4] < m_minYcoord) { m_minYcoord = v[4]; } if(v[4] > m_maxYcoord) { m_maxYcoord = v[4]; } if(v[5] < m_minZcoord) { m_minZcoord = v[5]; } if(v[5] > m_maxZcoord) { m_maxZcoord = v[5]; } if(v[6] < m_minXcoord) { m_minXcoord = v[6]; } if(v[6] > m_maxXcoord) { m_maxXcoord = v[6]; } if(v[7] < m_minYcoord) { m_minYcoord = v[7]; } if(v[7] > m_maxYcoord) { m_maxYcoord = v[7]; } if(v[8] < m_minZcoord) { m_minZcoord = v[8]; } if(v[8] > m_maxZcoord) { m_maxZcoord = v[8]; } if(v[9] < m_minXcoord) { m_minXcoord = v[9]; } if(v[9] > m_maxXcoord) { m_maxXcoord = v[9]; } if(v[10] < m_minYcoord) { m_minYcoord = v[10]; } if(v[10] > m_maxYcoord) { m_maxYcoord = v[10]; } if(v[11] < m_minZcoord) { m_minZcoord = v[11]; } if(v[11] > m_maxZcoord) { m_maxZcoord = v[11]; } m_FaceNormals[3 * t + 0] = v[0]; m_FaceNormals[3 * t + 1] = v[1]; m_FaceNormals[3 * t + 2] = v[2]; nodes[3 * (3 * t + 0) + 0] = v[3]; nodes[3 * (3 * t + 0) + 1] = v[4]; nodes[3 * (3 * t + 0) + 2] = v[5]; nodes[3 * (3 * t + 1) + 0] = v[6]; nodes[3 * (3 * t + 1) + 1] = v[7]; nodes[3 * (3 * t + 1) + 2] = v[8]; nodes[3 * (3 * t + 2) + 0] = v[9]; nodes[3 * (3 * t + 2) + 1] = v[10]; nodes[3 * (3 * t + 2) + 2] = v[11]; triangles[t * 3] = 3 * t + 0; triangles[t * 3 + 1] = 3 * t + 1; triangles[t * 3 + 2] = 3 * t + 2; } return; }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void WriteTriangleGeometry::execute() { int err = 0; setErrorCondition(err); dataCheck(); if(getErrorCondition() < 0) { return; } DataContainer::Pointer dataContainer = getDataContainerArray()->getPrereqDataContainer<AbstractFilter>(this, getDataContainerSelection()); TriangleGeom::Pointer triangleGeom = dataContainer->getGeometryAs<TriangleGeom>(); QString geometryType = triangleGeom->getGeometryTypeAsString(); float* nodes = triangleGeom->getVertexPointer(0); int64_t* triangles = triangleGeom->getTriPointer(0); qint64 numNodes = triangleGeom->getNumberOfVertices(); qint64 maxNodeId = numNodes - 1; int64_t numTriangles = triangleGeom->getNumberOfTris(); // ++++++++++++++ Write the Nodes File +++++++++++++++++++++++++++++++++++++++++++ // Make sure any directory path is also available as the user may have just typed // in a path without actually creating the full path notifyStatusMessage(getHumanLabel(), "Writing Nodes Text File"); QFileInfo fi(getOutputNodesFile()); QDir parentPath = fi.path(); if(!parentPath.mkpath(".")) { QString ss = QObject::tr("Error creating parent path '%1'").arg(parentPath.absolutePath()); notifyErrorMessage(getHumanLabel(), ss, -1); setErrorCondition(-1); return; } FILE* nodesFile = NULL; nodesFile = fopen(getOutputNodesFile().toLatin1().data(), "wb"); if (NULL == nodesFile) { setErrorCondition(-100); notifyErrorMessage(getHumanLabel(), "Error opening Nodes file for writing", -100); return; } fprintf(nodesFile, "# All lines starting with '#' are comments\n"); fprintf(nodesFile, "# DREAM.3D Nodes file\n"); fprintf(nodesFile, "# DREAM.3D Version %s\n", SIMPLib::Version::Complete().toLatin1().constData()); fprintf(nodesFile, "# Node Data is X Y Z space delimited.\n"); fprintf(nodesFile, "Node Count: %lld\n", numNodes); for (int i = 0; i < numNodes; i++) { fprintf(nodesFile, "%8.5f %8.5f %8.5f\n", nodes[i * 3], nodes[i * 3 + 1], nodes[i * 3 + 2]); } fclose(nodesFile); // ++++++++++++++ Write the Triangles File +++++++++++++++++++++++++++++++++++++++++++ notifyStatusMessage(getHumanLabel(), "Writing Triangles Text File"); QFileInfo triFI(getOutputTrianglesFile()); parentPath = triFI.path(); if(!parentPath.mkpath(".")) { QString ss = QObject::tr("Error creating parent path '%1'").arg(parentPath.absolutePath()); notifyErrorMessage(getHumanLabel(), ss, -1); setErrorCondition(-1); return; } FILE* triFile = fopen(getOutputTrianglesFile().toLatin1().data(), "wb"); if (NULL == triFile) { setErrorCondition(-100); notifyErrorMessage(getHumanLabel(), "Error opening Triangles file for writing", -100); return; } fprintf(triFile, "# All lines starting with '#' are comments\n"); fprintf(triFile, "# DREAM.3D Triangle file\n"); fprintf(triFile, "# DREAM.3D Version %s\n", SIMPLib::Version::Complete().toLatin1().constData()); fprintf(triFile, "# Each Triangle consists of 3 Node Ids.\n"); fprintf(triFile, "# NODE IDs START AT 0.\n"); fprintf(triFile, "Geometry Type: %s\n", geometryType.toLatin1().constData()); fprintf(triFile, "Node Count: %lld\n", numNodes); fprintf(triFile, "Max Node Id: %lld\n", maxNodeId ); fprintf(triFile, "Triangle Count: %lld\n", (long long int)(numTriangles)); int n1, n2, n3; for (int64_t j = 0; j < numTriangles; ++j) { n1 = triangles[j * 3]; n2 = triangles[j * 3 + 1]; n3 = triangles[j * 3 + 2]; fprintf(triFile, "%d %d %d\n", n1, n2, n3); } fclose(triFile); /* Let the GUI know we are done with this filter */ notifyStatusMessage(getHumanLabel(), "Complete"); }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- int32_t FindNRingNeighbors::generate(TriangleGeom::Pointer triangleGeom, int32_t* faceLabels) { int64_t* triangles = triangleGeom->getTriPointer(0); int32_t err = 0; //Clear out all the previous triangles. m_NRingTriangles.clear(); // Make sure we have the proper connectivity built ElementDynamicList::Pointer node2TrianglePtr = triangleGeom->getElementsContainingVert(); if (node2TrianglePtr.get() == NULL) { err = triangleGeom->findElementsContainingVert(); if (err < 0) { return err; } node2TrianglePtr = triangleGeom->getElementsContainingVert(); } // Figure out these boolean values for a sanity check bool check0 = faceLabels[m_TriangleId * 2] == m_RegionId0 && faceLabels[m_TriangleId * 2 + 1] == m_RegionId1; bool check1 = faceLabels[m_TriangleId * 2 + 1] == m_RegionId0 && faceLabels[m_TriangleId * 2] == m_RegionId1; #if 1 if ( check0 == false && check1 == false) { qDebug() << "FindNRingNeighbors Seed triangle ID does not have a matching Region ID for " << m_RegionId0 << " & " << m_RegionId1 << "\n"; qDebug() << "Region Ids are: " << faceLabels[m_TriangleId * 2] << " & " << faceLabels[m_TriangleId * 2 + 1] << "\n"; return err; } #endif // Add our seed triangle m_NRingTriangles.insert(m_TriangleId); for (int64_t ring = 0; ring < m_Ring; ++ring) { // Make a copy of the 1 Ring Triangles that we just found so that we can use those triangles as the // seed triangles for the 2 Ring triangles UniqueFaceIds_t lcvTriangles(m_NRingTriangles); // Now that we have the 1 ring triangles, get the 2 Ring neighbors from that list for (UniqueFaceIds_t::iterator triIter = lcvTriangles.begin(); triIter != lcvTriangles.end(); ++triIter) { int64_t triangleIdx = *triIter; // For each node, get the triangle ids that the node belongs to for(int32_t i = 0; i < 3; ++i) { // Get all the triangles for this Node id uint16_t tCount = node2TrianglePtr->getNumberOfElements(triangles[triangleIdx * 3 + i]); int64_t* data = node2TrianglePtr->getElementListPointer(triangles[triangleIdx * 3 + i]); // Copy all the triangles into our "2Ring" set which will be the unique set of triangle ids for (uint16_t t = 0; t < tCount; ++t) { int64_t tid = data[t]; check0 = faceLabels[tid * 2] == m_RegionId0 && faceLabels[tid * 2 + 1] == m_RegionId1; check1 = faceLabels[tid * 2 + 1] == m_RegionId0 && faceLabels[tid * 2] == m_RegionId1; if (check0 == true || check1 == true) { m_NRingTriangles.insert(tid); } } } } } return err; }
// ----------------------------------------------------------------------------- // // ----------------------------------------------------------------------------- void WriteStlFile::execute() { int32_t err = 0; setErrorCondition(0); dataCheck(); if(getErrorCondition() < 0) { return; } // Make sure any directory path is also available as the user may have just typed // in a path without actually creating the full path QDir stlDir(getOutputStlDirectory()); if (!stlDir.mkpath(".")) { QString ss = QObject::tr("Error creating parent path '%1'").arg(getOutputStlDirectory()); notifyErrorMessage(getHumanLabel(), ss, -1); setErrorCondition(-1); return; } TriangleGeom::Pointer triangleGeom = getDataContainerArray()->getDataContainer(getSurfaceMeshFaceLabelsArrayPath().getDataContainerName())->getGeometryAs<TriangleGeom>(); float* nodes = triangleGeom->getVertexPointer(0); int64_t* triangles = triangleGeom->getTriPointer(0); int64_t nTriangles = triangleGeom->getNumberOfTris(); if (nTriangles > std::numeric_limits<int32_t>::max()) { QString ss = QObject::tr("The number of triangles is %1, but the STL specification only supports triangle counts up to %2").arg(nTriangles).arg(std::numeric_limits<int32_t>::max()); notifyErrorMessage(getHumanLabel(), ss, -1); setErrorCondition(-1); return; } // Store all the unique Spins QMap<int32_t, int32_t> uniqueGrainIdtoPhase; if (m_GroupByPhase == true) { for (int64_t i = 0; i < nTriangles; i++) { uniqueGrainIdtoPhase.insert(m_SurfaceMeshFaceLabels[i * 2], m_SurfaceMeshFacePhases[i * 2]); uniqueGrainIdtoPhase.insert(m_SurfaceMeshFaceLabels[i * 2 + 1], m_SurfaceMeshFacePhases[i * 2 + 1]); } } else { for (int64_t i = 0; i < nTriangles; i++) { uniqueGrainIdtoPhase.insert(m_SurfaceMeshFaceLabels[i * 2], 0); uniqueGrainIdtoPhase.insert(m_SurfaceMeshFaceLabels[i * 2 + 1], 0); } } unsigned char data[50]; float* normal = (float*)data; float* vert1 = (float*)(data + 12); float* vert2 = (float*)(data + 24); float* vert3 = (float*)(data + 36); uint16_t* attrByteCount = (uint16_t*)(data + 48); *attrByteCount = 0; size_t totalWritten = 0; float u[3] = { 0.0f, 0.0f, 0.0f }, w[3] = { 0.0f, 0.0f, 0.0f }; float length = 0.0f; int32_t spin = 0; int32_t triCount = 0; //Loop over the unique Spins for (QMap<int32_t, int32_t>::iterator spinIter = uniqueGrainIdtoPhase.begin(); spinIter != uniqueGrainIdtoPhase.end(); ++spinIter ) { spin = spinIter.key(); // Generate the output file name QString filename = getOutputStlDirectory() + "/" + getOutputStlPrefix(); if (m_GroupByPhase == true) { filename = filename + QString("Ensemble_") + QString::number(spinIter.value()) + QString("_"); } filename = filename + QString("Feature_") + QString::number(spin) + ".stl"; FILE* f = fopen(filename.toLatin1().data(), "wb"); { QString ss = QObject::tr("Writing STL for Feature Id %1").arg(spin); notifyStatusMessage(getMessagePrefix(), getHumanLabel(), ss); } QString header = "DREAM3D Generated For Feature ID " + QString::number(spin); if (m_GroupByPhase == true) { header = header + " Phase " + QString::number(spinIter.value()); } err = writeHeader(f, header, 0); if (err < 0) { } triCount = 0; // Reset this to Zero. Increment for every triangle written // Loop over all the triangles for this spin for (int64_t t = 0; t < nTriangles; ++t) { // Get the true indices of the 3 nodes int64_t nId0 = triangles[t * 3]; int64_t nId1 = triangles[t * 3 + 1]; int64_t nId2 = triangles[t * 3 + 2]; vert1[0] = static_cast<float>(nodes[nId0 * 3]); vert1[1] = static_cast<float>(nodes[nId0 * 3 + 1]); vert1[2] = static_cast<float>(nodes[nId0 * 3 + 2]); if (m_SurfaceMeshFaceLabels[t * 2] == spin) { //winding = 0; // 0 = Write it using forward spin } else if (m_SurfaceMeshFaceLabels[t * 2 + 1] == spin) { //winding = 1; // Write it using backward spin // Switch the 2 node indices int64_t temp = nId1; nId1 = nId2; nId2 = temp; } else { continue; // We do not match either spin so move to the next triangle } vert2[0] = static_cast<float>(nodes[nId1 * 3]); vert2[1] = static_cast<float>(nodes[nId1 * 3 + 1]); vert2[2] = static_cast<float>(nodes[nId1 * 3 + 2]); vert3[0] = static_cast<float>(nodes[nId2 * 3]); vert3[1] = static_cast<float>(nodes[nId2 * 3 + 1]); vert3[2] = static_cast<float>(nodes[nId2 * 3 + 2]); // Compute the normal u[0] = vert2[0] - vert1[0]; u[1] = vert2[1] - vert1[1]; u[2] = vert2[2] - vert1[2]; w[0] = vert3[0] - vert1[0]; w[1] = vert3[1] - vert1[1]; w[2] = vert3[2] - vert1[2]; normal[0] = u[1] * w[2] - u[2] * w[1]; normal[1] = u[2] * w[0] - u[0] * w[2]; normal[2] = u[0] * w[1] - u[1] * w[0]; length = sqrtf(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); normal[0] = normal[0] / length; normal[1] = normal[1] / length; normal[2] = normal[2] / length; totalWritten = fwrite(data, 1, 50, f); if (totalWritten != 50) { QString ss = QObject::tr("Error Writing STL File. Not enough elements written for Feature Id %1. Wrote %2 of 50.").arg(spin).arg(totalWritten); notifyErrorMessage(getHumanLabel(), ss, -1201); } triCount++; } fclose(f); err = writeNumTrianglesToFile(filename, triCount); } setErrorCondition(0); notifyStatusMessage(getHumanLabel(), "Complete"); return; }