//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void caf::Viewer::optimizeClippingPlanes() { if (m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) { cvf::BoundingBox bb = m_renderingSequence->boundingBox(); if (!bb.isValid()) return; cvf::Vec3d eye, vrp, up; m_mainCamera->toLookAt(&eye, &vrp, &up); cvf::Vec3d viewdir = (vrp - eye).getNormalized(); double distEyeBoxCenterAlongViewDir = (bb.center() - eye)*viewdir; double farPlaneDist = distEyeBoxCenterAlongViewDir + bb.radius(); farPlaneDist = CVF_MIN(farPlaneDist, m_maxFarPlaneDistance); double nearPlaneDist = distEyeBoxCenterAlongViewDir - bb.radius(); if (nearPlaneDist < m_minNearPlaneDistance) nearPlaneDist = m_minNearPlaneDistance; if ( m_navigationPolicy.notNull()) { double pointOfInterestDist = (eye - m_navigationPolicy->pointOfInterest()).length(); nearPlaneDist = CVF_MIN( nearPlaneDist, pointOfInterestDist*0.2); } if (farPlaneDist <= nearPlaneDist) farPlaneDist = nearPlaneDist + 1.0; m_mainCamera->setProjectionAsPerspective(m_mainCamera->fieldOfViewYDeg(), nearPlaneDist, farPlaneDist); } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCellEdgeColors::minMaxCellEdgeValues(double& min, double& max) { double globalMin, globalMax; globalMin = HUGE_VAL; globalMax = -HUGE_VAL; size_t resultIndices[6]; this->gridScalarIndices(resultIndices); size_t idx; for (idx = 0; idx < 6; idx++) { if (resultIndices[idx] == cvf::UNDEFINED_SIZE_T) continue; { double cMin, cMax; m_reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(resultIndices[idx], cMin, cMax); globalMin = CVF_MIN(globalMin, cMin); globalMax = CVF_MAX(globalMax, cMax); } } min = globalMin; max = globalMax; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- String ProgramOptions::usageText(int maxWidth, int maxOptionWidth) const { if (maxWidth <= 1) maxWidth = 2; if (maxOptionWidth <= 0) maxOptionWidth = maxWidth/2; const String prefixStr = prefixString(); std::vector<String> optAndValArr; std::vector<String> descrArr; int optAndValMaxLen = 0; const size_t numOpts = m_optionSpecs.size(); for (size_t i = 0; i < numOpts; i++) { const OptionSpec* spec = m_optionSpecs.at(i); String optAndVal = prefixStr + spec->m_name + String(" ") + spec->m_valueSyntax; optAndValMaxLen = CVF_MAX(optAndValMaxLen, static_cast<int>(optAndVal.size())); optAndValArr.push_back(optAndVal); descrArr.push_back(spec->m_descr); } const int firstColWidth = static_cast<int>(CVF_MIN(optAndValMaxLen + 1, maxOptionWidth)); const String firstColBlanks = String("%1").arg("", firstColWidth); String retStr; for (size_t iopt = 0; iopt < numOpts; iopt++) { const String optAndVal = optAndValArr[iopt]; const int maxDescrWidth = CVF_MAX((maxWidth - firstColWidth), 1); std::vector<String> descrLines = breakStringIntoLines(descrArr[iopt], static_cast<size_t>(maxDescrWidth)); String s = String("%1 ").arg(optAndValArr[iopt], -(firstColWidth - 1)); if (s.size() > static_cast<size_t>(firstColWidth) && descrLines.size() > 0) { s += "\n" + firstColBlanks; } for (size_t i = 0; i < descrLines.size(); i++) { if (i > 0) { s += "\n" + firstColBlanks; } s += descrLines[i]; } retStr += s + String("\n"); } return retStr; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::minMaxCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& min, double& max) { min = HUGE_VAL; max = -HUGE_VAL; CVF_ASSERT(scalarResultIndex < resultCount()); if (timeStepIndex >= m_cellScalarResults[scalarResultIndex].size()) { return; } if (scalarResultIndex >= m_maxMinValuesPrTs.size()) { m_maxMinValuesPrTs.resize(scalarResultIndex+1); } if (timeStepIndex >= m_maxMinValuesPrTs[scalarResultIndex].size()) { m_maxMinValuesPrTs[scalarResultIndex].resize(timeStepIndex+1, std::make_pair(HUGE_VAL, -HUGE_VAL)); } if (m_maxMinValuesPrTs[scalarResultIndex][timeStepIndex].first != HUGE_VAL) { min = m_maxMinValuesPrTs[scalarResultIndex][timeStepIndex].first; max = m_maxMinValuesPrTs[scalarResultIndex][timeStepIndex].second; return; } if (scalarResultIndex == m_combinedTransmissibilityResultIndex) { size_t tranX, tranY, tranZ; if (!findTransmissibilityResults(tranX, tranY, tranZ)) return; double tranMin; double tranMax; minMaxCellScalarValues(tranX, timeStepIndex, tranMin, tranMax); min = CVF_MIN(tranMin, min); max = CVF_MAX(tranMax, max); minMaxCellScalarValues(tranY, timeStepIndex, tranMin, tranMax); min = CVF_MIN(tranMin, min); max = CVF_MAX(tranMax, max); minMaxCellScalarValues(tranZ, timeStepIndex, tranMin, tranMax); min = CVF_MIN(tranMin, min); max = CVF_MAX(tranMax, max); return; } std::vector<double>& values = m_cellScalarResults[scalarResultIndex][timeStepIndex]; size_t i; for (i = 0; i < values.size(); i++) { if (values[i] == HUGE_VAL) { continue; } if (values[i] < min) { min = values[i]; } if (values[i] > max) { max = values[i]; } } m_maxMinValuesPrTs[scalarResultIndex][timeStepIndex].first = min; m_maxMinValuesPrTs[scalarResultIndex][timeStepIndex].second= max; }
void RigCaseToCaseRangeFilterMapper::convertRangeFilter(const RimCellRangeFilter* srcFilter, RimCellRangeFilter* dstFilter, const RigMainGrid* eclGrid, const RigFemPart* femPart, bool femIsDestination) { CVF_ASSERT(srcFilter && eclGrid && dstFilter && femPart); CVF_ASSERT(srcFilter->gridIndex() == 0); // LGR not supported yet RigRangeEndPoints src; // Convert the (start, count) range filter vars to end point cell ijk { src.StartI = srcFilter->startIndexI() - 1; src.StartJ = srcFilter->startIndexJ() - 1; src.StartK = srcFilter->startIndexK() - 1; // Needs to subtract one more to have the end idx beeing // the last cell in the selection, not the first outside src.EndI = src.StartI + srcFilter->cellCountI() - 1; src.EndJ = src.StartJ + srcFilter->cellCountJ() - 1; src.EndK = src.StartK + srcFilter->cellCountK() - 1; } // Clamp the src end points to be inside the src model { size_t maxIIndex; size_t maxJIndex; size_t maxKIndex; // Clamp end if (femIsDestination) { maxIIndex = eclGrid->cellCountI()- 1; maxJIndex = eclGrid->cellCountJ()- 1; maxKIndex = eclGrid->cellCountK()- 1; } else { maxIIndex = femPart->structGrid()->cellCountI()- 1; maxJIndex = femPart->structGrid()->cellCountJ()- 1; maxKIndex = femPart->structGrid()->cellCountK()- 1; } src.EndI = CVF_MIN(src.EndI, maxIIndex); src.EndJ = CVF_MIN(src.EndJ, maxJIndex); src.EndK = CVF_MIN(src.EndK, maxKIndex); } // When using femPart as source we need to clamp the fem srcRange filter // to the extents of the ecl grid within the fem part before // doing the mapping. If not, the range filter corners will most likely be outside // the ecl grid, resulting in an undefined conversion. if (!femIsDestination) { RigRangeEndPoints eclMaxMin; eclMaxMin.StartI = 0; eclMaxMin.StartJ = 0; eclMaxMin.StartK = 0; eclMaxMin.EndI = eclGrid->cellCountI() - 1; eclMaxMin.EndJ = eclGrid->cellCountJ() - 1; eclMaxMin.EndK = eclGrid->cellCountK() - 1; RigRangeEndPoints eclExtInFem; convertRangeFilterEndPoints(eclMaxMin, eclExtInFem, eclGrid, femPart, true); src.StartI = CVF_MAX(src.StartI, eclExtInFem.StartI); src.StartJ = CVF_MAX(src.StartJ, eclExtInFem.StartJ); src.StartK = CVF_MAX(src.StartK, eclExtInFem.StartK); src.EndI = CVF_MIN(src.EndI , eclExtInFem.EndI); src.EndJ = CVF_MIN(src.EndJ , eclExtInFem.EndJ); src.EndK = CVF_MIN(src.EndK , eclExtInFem.EndK); } RigRangeEndPoints dst; convertRangeFilterEndPoints(src, dst, eclGrid, femPart, femIsDestination); // Populate the dst range filter with new data if ( dst.StartI != cvf::UNDEFINED_SIZE_T && dst.StartJ != cvf::UNDEFINED_SIZE_T && dst.StartK != cvf::UNDEFINED_SIZE_T && dst.EndI != cvf::UNDEFINED_SIZE_T && dst.EndJ != cvf::UNDEFINED_SIZE_T && dst.EndK != cvf::UNDEFINED_SIZE_T) { dstFilter->startIndexI = static_cast<int>(dst.StartI + 1); dstFilter->startIndexJ = static_cast<int>(dst.StartJ + 1); dstFilter->startIndexK = static_cast<int>(dst.StartK + 1); dstFilter->cellCountI = static_cast<int>(dst.EndI - (dst.StartI-1)); dstFilter->cellCountJ = static_cast<int>(dst.EndJ - (dst.StartJ-1)); dstFilter->cellCountK = static_cast<int>(dst.EndK - (dst.StartK-1)); } else { dstFilter->startIndexI = 1; dstFilter->startIndexJ = 1; dstFilter->startIndexK = 1; dstFilter->cellCountI = 0; dstFilter->cellCountJ = 0; dstFilter->cellCountK = 0; } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RigCaseToCaseRangeFilterMapper::convertRangeFilterEndPoints(const RigRangeEndPoints &src, RigRangeEndPoints &dst, const RigMainGrid* eclGrid, const RigFemPart* femPart, bool femIsDestination) { { struct RangeFilterCorner { RangeFilterCorner() : cellMatchType(APPROX_ON_COLLAPSED){} cvf::Vec3st ijk; CellMatchType cellMatchType; }; RangeFilterCorner rangeFilterMatches[8]; cvf::Vec3st srcRangeCube[8]; srcRangeCube[0] = cvf::Vec3st(src.StartI, src.StartJ, src.StartK); srcRangeCube[1] = cvf::Vec3st(src.EndI , src.StartJ, src.StartK); srcRangeCube[2] = cvf::Vec3st(src.EndI , src.EndJ , src.StartK); srcRangeCube[3] = cvf::Vec3st(src.StartI, src.EndJ , src.StartK); srcRangeCube[4] = cvf::Vec3st(src.StartI, src.StartJ, src.EndK); srcRangeCube[5] = cvf::Vec3st(src.EndI , src.StartJ, src.EndK); srcRangeCube[6] = cvf::Vec3st(src.EndI , src.EndJ , src.EndK); srcRangeCube[7] = cvf::Vec3st(src.StartI, src.EndJ , src.EndK); bool foundExactMatch = false; int cornerIdx = 0; int diagIdx = 6;// Index to diagonal corner for (cornerIdx = 0; cornerIdx < 4; ++cornerIdx) { diagIdx = (cornerIdx < 2) ? cornerIdx + 6 : cornerIdx + 2; if (femIsDestination) { rangeFilterMatches[cornerIdx].cellMatchType = findBestFemCellFromEclCell(eclGrid, srcRangeCube[cornerIdx][0], srcRangeCube[cornerIdx][1], srcRangeCube[cornerIdx][2], femPart, &(rangeFilterMatches[cornerIdx].ijk[0]), &(rangeFilterMatches[cornerIdx].ijk[1]), &(rangeFilterMatches[cornerIdx].ijk[2])); rangeFilterMatches[diagIdx].cellMatchType = findBestFemCellFromEclCell(eclGrid, srcRangeCube[diagIdx][0], srcRangeCube[diagIdx][1], srcRangeCube[diagIdx][2], femPart, &(rangeFilterMatches[diagIdx].ijk[0]), &(rangeFilterMatches[diagIdx].ijk[1]), &(rangeFilterMatches[diagIdx].ijk[2])); } else { rangeFilterMatches[cornerIdx].cellMatchType = findBestEclCellFromFemCell(femPart, srcRangeCube[cornerIdx][0], srcRangeCube[cornerIdx][1], srcRangeCube[cornerIdx][2], eclGrid, &(rangeFilterMatches[cornerIdx].ijk[0]), &(rangeFilterMatches[cornerIdx].ijk[1]), &(rangeFilterMatches[cornerIdx].ijk[2])); rangeFilterMatches[diagIdx].cellMatchType = findBestEclCellFromFemCell(femPart, srcRangeCube[diagIdx][0], srcRangeCube[diagIdx][1], srcRangeCube[diagIdx][2], eclGrid, &(rangeFilterMatches[diagIdx].ijk[0]), &(rangeFilterMatches[diagIdx].ijk[1]), &(rangeFilterMatches[diagIdx].ijk[2])); } if (rangeFilterMatches[cornerIdx].cellMatchType == EXACT && rangeFilterMatches[diagIdx].cellMatchType == EXACT) { foundExactMatch = true; break; } } // Get the start and end IJK from the matched corners if (foundExactMatch) { // Populate dst range filter from the diagonal that matches exact dst.StartI = CVF_MIN(rangeFilterMatches[cornerIdx].ijk[0], rangeFilterMatches[diagIdx].ijk[0]); dst.StartJ = CVF_MIN(rangeFilterMatches[cornerIdx].ijk[1], rangeFilterMatches[diagIdx].ijk[1]); dst.StartK = CVF_MIN(rangeFilterMatches[cornerIdx].ijk[2], rangeFilterMatches[diagIdx].ijk[2]); dst.EndI = CVF_MAX(rangeFilterMatches[cornerIdx].ijk[0], rangeFilterMatches[diagIdx].ijk[0]); dst.EndJ = CVF_MAX(rangeFilterMatches[cornerIdx].ijk[1], rangeFilterMatches[diagIdx].ijk[1]); dst.EndK = CVF_MAX(rangeFilterMatches[cornerIdx].ijk[2], rangeFilterMatches[diagIdx].ijk[2]); } else { // Look at the matches for each "face" of the range filter cube, // and use first exact match to determine the position of that "face" size_t faceIJKs[6] = {cvf::UNDEFINED_SIZE_T, cvf::UNDEFINED_SIZE_T,cvf::UNDEFINED_SIZE_T,cvf::UNDEFINED_SIZE_T,cvf::UNDEFINED_SIZE_T,cvf::UNDEFINED_SIZE_T}; for (int faceIdx = 0; faceIdx < 6; ++faceIdx) { int ijOrk = 0; if (faceIdx == cvf::StructGridInterface::POS_I || faceIdx == cvf::StructGridInterface::NEG_I) ijOrk = 0; if (faceIdx == cvf::StructGridInterface::POS_J || faceIdx == cvf::StructGridInterface::NEG_J) ijOrk = 1; if (faceIdx == cvf::StructGridInterface::POS_K || faceIdx == cvf::StructGridInterface::NEG_K) ijOrk = 2; cvf::ubyte surfCorners[4]; cvf::StructGridInterface::cellFaceVertexIndices((cvf::StructGridInterface::FaceType) faceIdx , surfCorners); bool foundAcceptedMatch = false; for (int cIdx = 0; cIdx < 4; ++cIdx) { if (rangeFilterMatches[surfCorners[cIdx]].cellMatchType == EXACT) { foundAcceptedMatch = true; faceIJKs[faceIdx] = rangeFilterMatches[surfCorners[cIdx]].ijk[ijOrk]; break; } } if (!foundAcceptedMatch) { // Take first match that is not related to a collapsed eclipse cell for (int cIdx = 0; cIdx < 4; ++cIdx) { if (rangeFilterMatches[surfCorners[cIdx]].cellMatchType == APPROX) { foundAcceptedMatch = true; faceIJKs[faceIdx] = rangeFilterMatches[surfCorners[cIdx]].ijk[ijOrk]; break; } } if (!foundAcceptedMatch) { // Only collapsed cell hits in this "face" // Todo: then use opposite face - range filter thickness // For now, just select the first faceIJKs[faceIdx] = rangeFilterMatches[surfCorners[0]].ijk[ijOrk]; } } } #ifdef DEBUG for (int faceIdx = 0; faceIdx <6; ++faceIdx) {CVF_TIGHT_ASSERT(faceIJKs[faceIdx] != cvf::UNDEFINED_SIZE_T);} #endif dst.EndI = faceIJKs[cvf::StructGridInterface::POS_I]; dst.StartI = faceIJKs[cvf::StructGridInterface::NEG_I]; dst.EndJ = faceIJKs[cvf::StructGridInterface::POS_J]; dst.StartJ = faceIJKs[cvf::StructGridInterface::NEG_J]; dst.EndK = faceIJKs[cvf::StructGridInterface::POS_K]; dst.StartK = faceIJKs[cvf::StructGridInterface::NEG_K]; } } }
//-------------------------------------------------------------------------------------------------- /// Generate surface representation of the specified cut plane /// /// \note Will compute normals before returning geometry //-------------------------------------------------------------------------------------------------- void StructGridCutPlane::computeCutPlane() { DebugTimer tim("StructGridCutPlane::computeCutPlane", DebugTimer::DISABLED); bool doMapScalar = false; if (m_mapScalarSetIndex != UNDEFINED_UINT && m_scalarMapper.notNull()) { doMapScalar = true; } uint cellCountI = m_grid->cellCountI(); uint cellCountJ = m_grid->cellCountJ(); uint cellCountK = m_grid->cellCountK(); // Clear any current data m_vertices.clear(); m_vertexScalars.clear(); m_triangleIndices.clear(); m_meshLineIndices.clear(); // The indexing conventions for vertices and // edges used in the algorithm: // edg verts // 4-------------5 *------4------* 0 0 - 1 // /| /| /| /| 1 1 - 2 // / | / | 7/ | 5/ | 2 2 - 3 // / | / | |z / 8 / 9 3 3 - 0 // 7-------------6 | | /y *------6------* | 4 4 - 5 // | | | | |/ | | | | 5 5 - 6 // | 0---------|---1 *---x | *------0--|---* 6 6 - 7 // | / | / 11 / 10 / 7 7 - 4 // | / | / | /3 | /1 8 0 - 4 // |/ |/ |/ |/ 9 1 - 5 // 3-------------2 *------2------* 10 2 - 6 // vertex indices edge indices 11 3 - 7 // uint k; for (k = 0; k < cellCountK; k++) { uint j; for (j = 0; j < cellCountJ; j++) { uint i; for (i = 0; i < cellCountI; i++) { size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k); Vec3d minCoord; Vec3d maxCoord; m_grid->cellMinMaxCordinates(cellIndex, &minCoord, &maxCoord); // Early reject for cells outside clipping box if (m_clippingBoundingBox.isValid()) { BoundingBox cellBB(minCoord, maxCoord); if (!m_clippingBoundingBox.intersects(cellBB)) { continue; } } // Check if plane intersects this cell and skip if it doesn't if (!isCellIntersectedByPlane(m_plane, minCoord, maxCoord)) { continue; } GridCell cell; bool isClipped = false; if (m_clippingBoundingBox.isValid()) { if (!m_clippingBoundingBox.contains(minCoord) || !m_clippingBoundingBox.contains(maxCoord)) { isClipped = true; minCoord.x() = CVF_MAX(minCoord.x(), m_clippingBoundingBox.min().x()); minCoord.y() = CVF_MAX(minCoord.y(), m_clippingBoundingBox.min().y()); minCoord.z() = CVF_MAX(minCoord.z(), m_clippingBoundingBox.min().z()); maxCoord.x() = CVF_MIN(maxCoord.x(), m_clippingBoundingBox.max().x()); maxCoord.y() = CVF_MIN(maxCoord.y(), m_clippingBoundingBox.max().y()); maxCoord.z() = CVF_MIN(maxCoord.z(), m_clippingBoundingBox.max().z()); } } cell.p[0].set(minCoord.x(), maxCoord.y(), minCoord.z()); cell.p[1].set(maxCoord.x(), maxCoord.y(), minCoord.z()); cell.p[2].set(maxCoord.x(), minCoord.y(), minCoord.z()); cell.p[3].set(minCoord.x(), minCoord.y(), minCoord.z()); cell.p[4].set(minCoord.x(), maxCoord.y(), maxCoord.z()); cell.p[5].set(maxCoord.x(), maxCoord.y(), maxCoord.z()); cell.p[6].set(maxCoord.x(), minCoord.y(), maxCoord.z()); cell.p[7].set(minCoord.x(), minCoord.y(), maxCoord.z()); // Fetch scalar values double cellScalarValue = 0; if (doMapScalar) { cellScalarValue = m_grid->cellScalar(m_mapScalarSetIndex, i, j, k); // If we're doing node averaging we must populate grid cell with scalar values interpolated to the grid points if (m_mapNodeAveragedScalars) { if (isClipped) { double scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[0], &scalarVal)) cell.s[0] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[1], &scalarVal)) cell.s[1] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[2], &scalarVal)) cell.s[2] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[3], &scalarVal)) cell.s[3] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[4], &scalarVal)) cell.s[4] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[5], &scalarVal)) cell.s[5] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[6], &scalarVal)) cell.s[6] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[7], &scalarVal)) cell.s[7] = scalarVal; } else { cell.s[0] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j + 1, k); cell.s[1] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j + 1, k); cell.s[2] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j, k); cell.s[3] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j, k); cell.s[4] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j + 1, k + 1); cell.s[5] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j + 1, k + 1); cell.s[6] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j, k + 1); cell.s[7] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j, k + 1); } } } Triangles triangles; uint numTriangles = polygonise(m_plane, cell, &triangles); if (numTriangles > 0) { // Add all the referenced vertices // At the same time registering their index in the 'global' vertex list uint globalVertexIndices[12]; int iv; for (iv = 0; iv < 12; iv++) { if (triangles.usedVertices[iv]) { globalVertexIndices[iv] = static_cast<uint>(m_vertices.size()); m_vertices.push_back(Vec3f(triangles.vertices[iv])); if (doMapScalar) { if (m_mapNodeAveragedScalars) { m_vertexScalars.push_back(triangles.scalars[iv]); } else { m_vertexScalars.push_back(cellScalarValue); } } } else { globalVertexIndices[iv] = UNDEFINED_UINT; } } // Build triangles from the cell const size_t prevNumTriangleIndices = m_triangleIndices.size(); uint t; for (t = 0; t < numTriangles; t++) { m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t]]); m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t + 1]]); m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t + 2]]); } // Add mesh line indices addMeshLineIndices(&m_triangleIndices[prevNumTriangleIndices], numTriangles); } } } } //Trace::show("Vertices:%d TriConns:%d Tris:%d", m_vertices.size(), m_triangleIndices.size(), m_triangleIndices.size()/3); tim.reportTimeMS(); }