示例#1
0
//--------------------------------------------------------------------------------------------------
/// 
//--------------------------------------------------------------------------------------------------
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);
    }
}
示例#2
0
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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;
}
示例#3
0
//--------------------------------------------------------------------------------------------------
/// 
//--------------------------------------------------------------------------------------------------
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();
}