// clang-format off

#include "cafHexGridIntersectionTools.h"

#include "../LibCore/cvfPlane.h"
#include <cmath>

#include <algorithm>
#include <array>

namespace external
{
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
// HexGridIntersectionTools::ClipVx::ClipVx()
//    : vx(cvf::Vec3d::ZERO),
//      normDistFromEdgeVx1(HUGE_VAL),
//      clippedEdgeVx1Id(-1),
//      clippedEdgeVx2Id(-1),
//      isVxIdsNative(true),
//      derivedVxLevel(-1)
//{
//}
//

//--------------------------------------------------------------------------------------------------
/// Find intersection between a line segment and a plane
///
/// \param a            Start of line segment
/// \param b            End of line segment
/// \param intersection Returns intersection point along the infinite line defined by a-b
/// \param normalizedDistFromA Returns the normalized (0..1) position from a to b of the intersection point.
///                            Will return values along the infinite line defined by the a-b direcion,
///                            and HUGE_VAL if plane and line are parallel.
/// \param epsilon      Tolerance margin for accepting the position being within (0..1)
///
/// \return True if line segment intersects the plane
//--------------------------------------------------------------------------------------------------
bool HexGridIntersectionTools::planeLineIntersect( const cvf::Plane& plane,
                                                   const cvf::Vec3d& a,
                                                   const cvf::Vec3d& b,
                                                   cvf::Vec3d*       intersection,
                                                   double*           normalizedDistFromA,
                                                   double            epsilon )
{
    // From Real-Time Collision Detection by Christer Eriscon, published by Morgen Kaufmann Publishers, (c) 2005
    // Elsevier Inc

    cvf::Vec3d ab     = b - a;
    cvf::Vec3d normal = plane.normal();

    double normDotAB = normal * ab;
    if ( normDotAB == 0 )
    {
        ( *normalizedDistFromA ) = HUGE_VAL;
        return false;
    }

    double interpolationParameter = ( -plane.D() - ( normal * a ) ) / normDotAB;

    ( *intersection )        = a + interpolationParameter * ab;
    ( *normalizedDistFromA ) = interpolationParameter;

    return ( interpolationParameter >= -epsilon && interpolationParameter <= 1.0 + epsilon );
}

//--------------------------------------------------------------------------------------------------
/// Returns whether the triangle was hit by the plane.
/// isMostVxesOnPositiveSide returns true if all or two of the vxes is on the positive side of the plane.
/// newVx1/2.vx1ClippedEdge returns the index of the single vx that is alone on one side of the plane.
/// Going newVx1 to newVx2 will make the top triangle same winding as the original triangle,
/// and the quad opposite winding

// The permutations except for the trivial cases where all vertices are in front or behind plane:
//
//
// 1. Single vertex on positive side of plane => isMostVxesOnPositiveSide = false
//
//  +\   /\3               /\3   /+          /\3        .
//    \ /  \              /  \  /       +   /  \   +    .
//     \2   \            /    \/1       __1/____\2__    .
//    / \    \          /     /\          /      \      .
//  1/___\1___\2      1/____2/__\2      1/________\2    .
//       +\                 /+
//
//
// 2. Two vertices vertex on positive side of plane => isMostVxesOnPositiveSide = true
//
//     \+  /\3               /\3  +/        /\3         .
//      \ /  \              /  \  /        /  \         .
//       \2   \            /    \/1    __1/____\2__     .
//      / \    \          /     /\     + /      \ +     .
//    1/___\1___\2      1/____2/__\2   1/________\2     .
//          \+               +/
//
// 3. The special cases of touching one vertex, either exactly or "close enough"
//    in finite precision. These occur for both 2. and 3 and in any rotation.
//
//    a) Should not be counted      b) May need a tolerance margin to intersect
//       as intersecting:              both 1->3 and 2->3 as it is theoretically required to:
//                                   3
//        \        /\               /|\      .
//         \      /  \             / | \     .
//          \    /    \           /  |  \    .
//           \  /      \         /   |   \   .
//            \/________\       /____|____\  .
//             \               1     |     2

//--------------------------------------------------------------------------------------------------

bool HexGridIntersectionTools::planeTriangleIntersection( const cvf::Plane& plane,
                                                          const cvf::Vec3d& p1,
                                                          size_t            p1Id,
                                                          const cvf::Vec3d& p2,
                                                          size_t            p2Id,
                                                          const cvf::Vec3d& p3,
                                                          size_t            p3Id,
                                                          ClipVx*           newVx1,
                                                          ClipVx*           newVx2,
                                                          bool*             isMostVxesOnPositiveSide )
{
    const double nonDimensionalTolerance = 1.0e-8;

    double sqrSignedDistances[3];
    sqrSignedDistances[0] = plane.distanceSquared( p1 );
    sqrSignedDistances[1] = plane.distanceSquared( p2 );
    sqrSignedDistances[2] = plane.distanceSquared( p3 );

    double maxSqrAbsDistance = std::max( std::abs( sqrSignedDistances[0] ),
                                         std::max( std::abs( sqrSignedDistances[1] ), std::abs( sqrSignedDistances[2] ) ) );

    const double sqrDistanceTolerance = nonDimensionalTolerance * maxSqrAbsDistance;

    int onPosSide[3];
    onPosSide[0] = sqrSignedDistances[0] >= 0;
    onPosSide[1] = sqrSignedDistances[1] >= 0;
    onPosSide[2] = sqrSignedDistances[2] >= 0;

    const int numPositiveVertices = onPosSide[0] + onPosSide[1] + onPosSide[2];

    // The entire triangle is on the negative side
    // Clip everything
    if ( numPositiveVertices == 0 )
    {
        ( *isMostVxesOnPositiveSide ) = false;
        return false;
    }

    // All triangle vertices are on the positive side
    if ( numPositiveVertices == 3 )
    {
        ( *isMostVxesOnPositiveSide ) = true;
        return false;
    }

    ( *isMostVxesOnPositiveSide ) = ( numPositiveVertices == 2 );

    int topVx = 0;
    if ( numPositiveVertices == 1 )
    {
        if ( onPosSide[0] ) topVx = 1;
        if ( onPosSide[1] ) topVx = 2;
        if ( onPosSide[2] ) topVx = 3;

        // Case 3a: Two negative distances and the last is within tolerance of zero.
        if ( topVx > 0 && sqrSignedDistances[topVx - 1] < sqrDistanceTolerance )
        {
            return false;
        }
    }
    else if ( numPositiveVertices == 2 )
    {
        if ( !onPosSide[0] ) topVx = 1;
        if ( !onPosSide[1] ) topVx = 2;
        if ( !onPosSide[2] ) topVx = 3;

        // Case 3a: Two positive distances and the last is within tolerance of zero.
        if ( topVx > 0 && sqrSignedDistances[topVx - 1] > -sqrDistanceTolerance )
        {
            return false;
        }
    }
    else
    {
        CVF_ASSERT( false );
    }

    [[maybe_unused]] bool ok1 = false;
    [[maybe_unused]] bool ok2 = false;

    if ( topVx == 1 )
    {
        ok1                          = planeLineIntersect( plane, p1, p2, &( ( *newVx1 ).vx ), &( ( *newVx1 ).normDistFromEdgeVx1 ), nonDimensionalTolerance );
        ( *newVx1 ).clippedEdgeVx1Id = p1Id;
        ( *newVx1 ).clippedEdgeVx2Id = p2Id;
        ok2                          = planeLineIntersect( plane, p1, p3, &( ( *newVx2 ).vx ), &( ( *newVx2 ).normDistFromEdgeVx1 ), nonDimensionalTolerance );
        ( *newVx2 ).clippedEdgeVx1Id = p1Id;
        ( *newVx2 ).clippedEdgeVx2Id = p3Id;
    }
    else if ( topVx == 2 )
    {
        ok1                          = planeLineIntersect( plane, p2, p3, &( ( *newVx1 ).vx ), &( ( *newVx1 ).normDistFromEdgeVx1 ), nonDimensionalTolerance );
        ( *newVx1 ).clippedEdgeVx1Id = p2Id;
        ( *newVx1 ).clippedEdgeVx2Id = p3Id;
        ok2                          = planeLineIntersect( plane, p2, p1, &( ( *newVx2 ).vx ), &( ( *newVx2 ).normDistFromEdgeVx1 ), nonDimensionalTolerance );
        ( *newVx2 ).clippedEdgeVx1Id = p2Id;
        ( *newVx2 ).clippedEdgeVx2Id = p1Id;
    }
    else if ( topVx == 3 )
    {
        ok1                          = planeLineIntersect( plane, p3, p1, &( ( *newVx1 ).vx ), &( ( *newVx1 ).normDistFromEdgeVx1 ), nonDimensionalTolerance );
        ( *newVx1 ).clippedEdgeVx1Id = p3Id;
        ( *newVx1 ).clippedEdgeVx2Id = p1Id;
        ok2                          = planeLineIntersect( plane, p3, p2, &( ( *newVx2 ).vx ), &( ( *newVx2 ).normDistFromEdgeVx1 ), nonDimensionalTolerance );
        ( *newVx2 ).clippedEdgeVx1Id = p3Id;
        ( *newVx2 ).clippedEdgeVx2Id = p2Id;
    }
    else
    {
        CVF_ASSERT( false );
    }

    // CVF_TIGHT_ASSERT(ok1 && ok2);

    return true;
}

//--------------------------------------------------------------------------------------------------
//
//
//           P2        P2               P2             P2
//           Keep      Keep             Keep           Keep
//           None      Top    3         Quad           All
//            |         |     +         |               |
//            |         |    / \        |               |
//      |     |    |    |   /   \  |    |       |       |
//      |     |    |    |  /     \ |    |       |       |
//      |     |    |    | /       \|    |       |       |
//      |     |    |    |/        1+    |       |       |
//      |     |    |    +2         |\   |       |       |
//      |     |    |   /|          | \  |       |       |
//      |     |    |  / |          |  \ |  _    |       |
//      |     |    | /  |          |   \| |\Dir |       |
//      |     |    |/   |          |   1+   \   |       |
//      |     |    +2   |          |    |\   \  |       |
//      |     |   /|    |          |    | \     |       |
//      |     |  / |1   |1        2|   2|  \    |       |
//      |     | +--+----+----------+----+---+   |       |
//      |     |1   |    |          |    |    2  |       |
//     P1         P1              P1           P1
//     Keep       Keep            Keep         Keep
//     All        Quad            Top          None
//
//
// Clips the supplied triangles into new triangles returned in clippedTriangleVxes.
// New vertices have set isVxIdsNative = false and their vxIds is indices into triangleVxes
// The cellFaceForEachTriangleEdge refer to the edge after the corresponding triangle vertex.
// This method will keep the faces provided, while added edges is marked with no face = 6
//--------------------------------------------------------------------------------------------------

void HexGridIntersectionTools::clipTrianglesBetweenTwoParallelPlanes( const std::vector<ClipVx>& triangleVxes,
                                                                      const std::vector<int>& cellFaceForEachTriangleEdge,
                                                                      const cvf::Plane&       p1Plane,
                                                                      const cvf::Plane&       p2Plane,
                                                                      std::vector<ClipVx>*    clippedTriangleVxes,
                                                                      std::vector<int>* cellFaceForEachClippedTriangleEdge )
{
#define HT_NO_FACE 6

    size_t triangleCount = triangleVxes.size() / 3;

    for ( size_t tIdx = 0; tIdx < triangleCount; ++tIdx )
    {
        size_t triVxIdx = tIdx * 3;

        ClipVx newVx1OnP1;
        newVx1OnP1.isVxIdsNative = false;
        ClipVx newVx2OnP1;
        newVx2OnP1.isVxIdsNative = false;

        bool isMostVxesOnPositiveSideOfP1 = false;

        bool isIntersectingP1 = planeTriangleIntersection( p1Plane,
                                                           triangleVxes[triVxIdx + 0].vx,
                                                           triVxIdx + 0,
                                                           triangleVxes[triVxIdx + 1].vx,
                                                           triVxIdx + 1,
                                                           triangleVxes[triVxIdx + 2].vx,
                                                           triVxIdx + 2,
                                                           &newVx1OnP1,
                                                           &newVx2OnP1,
                                                           &isMostVxesOnPositiveSideOfP1 );

        if ( !isIntersectingP1 && !isMostVxesOnPositiveSideOfP1 )
        {
            continue; // Discard triangle
        }

        ClipVx newVx1OnP2;
        newVx1OnP2.isVxIdsNative = false;
        ClipVx newVx2OnP2;
        newVx2OnP2.isVxIdsNative = false;

        bool isMostVxesOnPositiveSideOfP2 = false;

        bool isIntersectingP2 = planeTriangleIntersection( p2Plane,
                                                           triangleVxes[triVxIdx + 0].vx,
                                                           triVxIdx + 0,
                                                           triangleVxes[triVxIdx + 1].vx,
                                                           triVxIdx + 1,
                                                           triangleVxes[triVxIdx + 2].vx,
                                                           triVxIdx + 2,
                                                           &newVx1OnP2,
                                                           &newVx2OnP2,
                                                           &isMostVxesOnPositiveSideOfP2 );

        if ( !isIntersectingP2 && !isMostVxesOnPositiveSideOfP2 )
        {
            continue; // Discard triangle
        }

        bool p1KeepAll  = ( !isIntersectingP1 && isMostVxesOnPositiveSideOfP1 );
        bool p2KeepAll  = ( !isIntersectingP2 && isMostVxesOnPositiveSideOfP2 );
        bool p1KeepQuad = ( isIntersectingP1 && isMostVxesOnPositiveSideOfP1 );
        bool p2KeepQuad = ( isIntersectingP2 && isMostVxesOnPositiveSideOfP2 );
        bool p1KeepTop  = ( isIntersectingP1 && !isMostVxesOnPositiveSideOfP1 );
        bool p2KeepTop  = ( isIntersectingP2 && !isMostVxesOnPositiveSideOfP2 );

        if ( p1KeepAll && p2KeepAll )
        {
            // Keep the triangle
            clippedTriangleVxes->push_back( triangleVxes[triVxIdx + 0] );
            clippedTriangleVxes->push_back( triangleVxes[triVxIdx + 1] );
            clippedTriangleVxes->push_back( triangleVxes[triVxIdx + 2] );

            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[triVxIdx + 0] );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[triVxIdx + 1] );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[triVxIdx + 2] );

            continue;
        }

        if ( p1KeepQuad && p2KeepAll )
        {
            // Split the resulting quad and add the two triangles
            clippedTriangleVxes->push_back( newVx2OnP1 );
            clippedTriangleVxes->push_back( newVx1OnP1 );
            clippedTriangleVxes->push_back( triangleVxes[newVx1OnP1.clippedEdgeVx2Id] );

            clippedTriangleVxes->push_back( triangleVxes[newVx1OnP1.clippedEdgeVx2Id] );
            clippedTriangleVxes->push_back( triangleVxes[newVx2OnP1.clippedEdgeVx2Id] );
            clippedTriangleVxes->push_back( newVx2OnP1 );

            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP1.clippedEdgeVx1Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP1.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP1.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            continue;
        }

        if ( p2KeepQuad && p1KeepAll )
        {
            // Split the resulting quad and add the two triangles
            clippedTriangleVxes->push_back( newVx2OnP2 );
            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( triangleVxes[newVx2OnP2.clippedEdgeVx2Id] );

            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( triangleVxes[newVx1OnP2.clippedEdgeVx2Id] );
            clippedTriangleVxes->push_back( triangleVxes[newVx2OnP2.clippedEdgeVx2Id] );

            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP2.clippedEdgeVx2Id] );

            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP2.clippedEdgeVx1Id] );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP2.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            continue;
        }

        if ( p1KeepTop && p2KeepAll )
        {
            // Add the top triangle
            clippedTriangleVxes->push_back( newVx1OnP1 );
            clippedTriangleVxes->push_back( newVx2OnP1 );
            clippedTriangleVxes->push_back( triangleVxes[newVx1OnP1.clippedEdgeVx1Id] );

            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP1.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP1.clippedEdgeVx1Id] );

            continue;
        }

        if ( p2KeepTop && p1KeepAll )
        {
            // Add the top triangle
            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( newVx2OnP2 );
            clippedTriangleVxes->push_back( triangleVxes[newVx1OnP2.clippedEdgeVx1Id] );

            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP2.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP2.clippedEdgeVx1Id] );

            continue;
        }

        if ( p1KeepQuad && p2KeepQuad )
        {
            // We end up with a pentagon.
            clippedTriangleVxes->push_back( newVx2OnP1 );
            clippedTriangleVxes->push_back( newVx1OnP1 );
            clippedTriangleVxes->push_back( newVx2OnP2 );

            clippedTriangleVxes->push_back( newVx2OnP2 );
            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( newVx2OnP1 );

            // Two variants. The original point might be along newVx1OnP1 to newVx2OnP2 or along newVx2OnP1 to newVx1OnP2
            if ( newVx1OnP1.clippedEdgeVx2Id == newVx2OnP2.clippedEdgeVx1Id )
            {
                clippedTriangleVxes->push_back( newVx2OnP1 );
                clippedTriangleVxes->push_back( newVx1OnP2 );
                clippedTriangleVxes->push_back( triangleVxes[newVx2OnP1.clippedEdgeVx2Id] );

                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP1.clippedEdgeVx1Id] );
                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP2.clippedEdgeVx1Id] );
                cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP1.clippedEdgeVx2Id] );
            }
            else
            {
                clippedTriangleVxes->push_back( newVx2OnP2 );
                clippedTriangleVxes->push_back( newVx1OnP1 );
                clippedTriangleVxes->push_back( triangleVxes[newVx2OnP2.clippedEdgeVx2Id] );

                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP2.clippedEdgeVx1Id] );
                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

                cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
                cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP1.clippedEdgeVx1Id] );
                cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP2.clippedEdgeVx2Id] );
            }

            continue;
        }

        if ( p1KeepQuad && p2KeepTop )
        {
            // We end up with a quad.
            clippedTriangleVxes->push_back( newVx1OnP1 );
            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( newVx2OnP1 );

            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( newVx2OnP2 );
            clippedTriangleVxes->push_back( newVx2OnP1 );

            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP1.clippedEdgeVx1Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP2.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            continue;
        }

        if ( p2KeepQuad && p1KeepTop )
        {
            // We end up with a quad.
            clippedTriangleVxes->push_back( newVx2OnP1 );
            clippedTriangleVxes->push_back( newVx2OnP2 );
            clippedTriangleVxes->push_back( newVx1OnP2 );

            clippedTriangleVxes->push_back( newVx2OnP1 );
            clippedTriangleVxes->push_back( newVx1OnP2 );
            clippedTriangleVxes->push_back( newVx1OnP1 );

            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx2OnP1.clippedEdgeVx2Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );
            cellFaceForEachClippedTriangleEdge->push_back( cellFaceForEachTriangleEdge[newVx1OnP2.clippedEdgeVx1Id] );
            cellFaceForEachClippedTriangleEdge->push_back( HT_NO_FACE );

            continue;
        }

        CVF_ASSERT( false );
    }
}

//--------------------------------------------------------------------------------------------------
// Creates a plane with normal perpendicular to the edge, pointing in the direction of the pointInNormalDirection
//--------------------------------------------------------------------------------------------------
static cvf::Plane createPlaneFromEdgeAndPointInNormalDirection( cvf::Vec3d ep1, cvf::Vec3d ep2, cvf::Vec3d pointInNormalDirection )
{
    cvf::Vec3d ep1ep2          = ep2 - ep1;
    cvf::Vec3d ep1pointforNorm = pointInNormalDirection - ep1;
    cvf::Vec3d triNormal       = ep1ep2 ^ ep1pointforNorm;
    cvf::Vec3d pointInPlane    = ep1 + triNormal;

    cvf::Plane plane;
    plane.setFromPoints( ep1, pointInPlane, ep2 );

    return plane;
}

//--------------------------------------------------------------------------------------------------
// Clips the supplied triangles into new triangles returned in clippedTriangleVxes.
// New vertices have set isVxIdsNative = false and their vxIds is indices into triangleVxes
// The cellFaceForEachTriangleEdge refer to the edge after the corresponding triangle vertex.
// This method will keep the faces provided, while added edges is marked with no face = 6
//--------------------------------------------------------------------------------------------------
void HexGridIntersectionTools::clipPlanarTrianglesWithInPlaneTriangle( const std::vector<cvf::Vec3d>& triangleVxes,
                                                                       const std::vector<int>& cellFaceForEachTriangleEdge,
                                                                       const cvf::Vec3d&       tp1,
                                                                       const cvf::Vec3d&       tp2,
                                                                       const cvf::Vec3d&       tp3,
                                                                       std::vector<cvf::Vec3d>* clippedTriangleVxes,
                                                                       std::vector<int>* cellFaceForEachClippedTriangleEdge )
{
#define HT_NO_FACE 6

    size_t triangleCount = triangleVxes.size() / 3;

    // Creating a plane for each of the edges of the clipping triangle
    std::array<cvf::Plane, 3> clipTrianglePlanes;

    clipTrianglePlanes[0] = createPlaneFromEdgeAndPointInNormalDirection( tp1, tp2, tp3 );
    clipTrianglePlanes[1] = createPlaneFromEdgeAndPointInNormalDirection( tp2, tp3, tp1 );
    clipTrianglePlanes[2] = createPlaneFromEdgeAndPointInNormalDirection( tp3, tp1, tp2 );

#define reserveSize 100

    std::vector<cvf::Vec3d> currentInputTriangleVxes;
    currentInputTriangleVxes.reserve( reserveSize );
    std::vector<int> currentInputCellFaceForEachTriangleEdge;
    currentInputCellFaceForEachTriangleEdge.reserve( reserveSize );
    std::vector<cvf::Vec3d> currentOutputTriangleVxes;
    currentOutputTriangleVxes.reserve( reserveSize );
    std::vector<int> currentOutputCellFaceForEachTriangleEdge;
    currentOutputCellFaceForEachTriangleEdge.reserve( reserveSize );

    for ( size_t tIdx = 0; tIdx < triangleCount; ++tIdx )
    {
        size_t triVxIdx = tIdx * 3;

        currentInputTriangleVxes.clear();
        currentInputCellFaceForEachTriangleEdge.clear();
        currentOutputTriangleVxes.clear();
        currentOutputCellFaceForEachTriangleEdge.clear();

        currentOutputTriangleVxes.push_back( triangleVxes[triVxIdx + 0] );
        currentOutputTriangleVxes.push_back( triangleVxes[triVxIdx + 1] );
        currentOutputTriangleVxes.push_back( triangleVxes[triVxIdx + 2] );

        currentOutputCellFaceForEachTriangleEdge.push_back( cellFaceForEachTriangleEdge[triVxIdx + 0] );
        currentOutputCellFaceForEachTriangleEdge.push_back( cellFaceForEachTriangleEdge[triVxIdx + 1] );
        currentOutputCellFaceForEachTriangleEdge.push_back( cellFaceForEachTriangleEdge[triVxIdx + 2] );

        ClipVx newVx1;
        newVx1.isVxIdsNative = false;
        ClipVx newVx2;
        newVx2.isVxIdsNative = false;

        for ( int planeIdx = 0; planeIdx < 3; ++planeIdx )
        {
            currentInputTriangleVxes.swap( currentOutputTriangleVxes );
            currentInputCellFaceForEachTriangleEdge.swap( currentOutputCellFaceForEachTriangleEdge );

            currentOutputTriangleVxes.clear();
            currentOutputCellFaceForEachTriangleEdge.clear();

            size_t inTriangleCount = currentInputTriangleVxes.size() / 3;

            for ( size_t inTrIdx = 0; inTrIdx < inTriangleCount; ++inTrIdx )
            {
                size_t inTriVxIdx = inTrIdx * 3;

                bool isMostVxesOnPositiveSide = false;

                bool isIntersectingPlane = planeTriangleIntersection( clipTrianglePlanes[planeIdx],
                                                                      currentInputTriangleVxes[inTriVxIdx + 0],
                                                                      inTriVxIdx + 0,
                                                                      currentInputTriangleVxes[inTriVxIdx + 1],
                                                                      inTriVxIdx + 1,
                                                                      currentInputTriangleVxes[inTriVxIdx + 2],
                                                                      inTriVxIdx + 2,
                                                                      &newVx1,
                                                                      &newVx2,
                                                                      &isMostVxesOnPositiveSide );

                if ( !isIntersectingPlane )
                {
                    // All on negative side: Discard triangle

                    if ( !isMostVxesOnPositiveSide )
                    {
                        continue;
                    }
                    else // All on positive side: keep all
                    {
                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[inTriVxIdx + 0] );
                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[inTriVxIdx + 1] );
                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[inTriVxIdx + 2] );

                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[inTriVxIdx + 0] );
                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[inTriVxIdx + 1] );
                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[inTriVxIdx + 2] );
                    }
                }
                else // intersecting
                {
                    if ( isMostVxesOnPositiveSide )
                    {
                        // We need the Quad

                        currentOutputTriangleVxes.push_back( newVx2.vx );
                        currentOutputTriangleVxes.push_back( newVx1.vx );
                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[newVx1.clippedEdgeVx2Id] );

                        currentOutputCellFaceForEachTriangleEdge.push_back( HT_NO_FACE );
                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[newVx1.clippedEdgeVx1Id] );
                        currentOutputCellFaceForEachTriangleEdge.push_back( HT_NO_FACE );

                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[newVx1.clippedEdgeVx2Id] );
                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[newVx2.clippedEdgeVx2Id] );
                        currentOutputTriangleVxes.push_back( newVx2.vx );

                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[newVx1.clippedEdgeVx2Id] );
                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[newVx2.clippedEdgeVx2Id] );
                        currentOutputCellFaceForEachTriangleEdge.push_back( HT_NO_FACE );
                    }
                    else
                    {
                        currentOutputTriangleVxes.push_back( newVx1.vx );
                        currentOutputTriangleVxes.push_back( newVx2.vx );
                        currentOutputTriangleVxes.push_back( currentInputTriangleVxes[newVx1.clippedEdgeVx1Id] );

                        currentOutputCellFaceForEachTriangleEdge.push_back( HT_NO_FACE );
                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[newVx2.clippedEdgeVx2Id] );
                        currentOutputCellFaceForEachTriangleEdge.push_back(
                            currentInputCellFaceForEachTriangleEdge[newVx1.clippedEdgeVx1Id] );
                    }
                }
            }
        }

        // Append the result of the completely clipped triangle to the output

        clippedTriangleVxes->insert( clippedTriangleVxes->end(),
                                     currentOutputTriangleVxes.begin(),
                                     currentOutputTriangleVxes.end() );
        cellFaceForEachClippedTriangleEdge->insert( cellFaceForEachClippedTriangleEdge->end(),
                                                    currentOutputCellFaceForEachTriangleEdge.begin(),
                                                    currentOutputCellFaceForEachTriangleEdge.end() );
    }
}

//--------------------------------------------------------------------------------------------------
/// Will return the intersection point. If the plane is outside the line, it returns the closest line endpoint
//--------------------------------------------------------------------------------------------------
cvf::Vec3d HexGridIntersectionTools::planeLineIntersectionForMC( const cvf::Plane& plane,
                                                                 const cvf::Vec3d& p1,
                                                                 const cvf::Vec3d& p2,
                                                                 double*           normalizedDistFromP1 )
{
    // From http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/
    //
    // P1 (x1,y1,z1) and P2 (x2,y2,z2)
    //
    // P = P1 + u (P2 - P1)
    //
    //          A*x1 + B*y1 + C*z1 + D
    // u = ---------------------------------
    //     A*(x1-x2) + B*(y1-y2) + C*(z1-z2)

    CVF_TIGHT_ASSERT( normalizedDistFromP1 );

    const cvf::Vec3d v = p2 - p1;

    ( *normalizedDistFromP1 ) = 0.0;

    double denominator = -( plane.A() * v.x() + plane.B() * v.y() + plane.C() * v.z() );
    if ( denominator != 0 )
    {
        double u = ( plane.A() * p1.x() + plane.B() * p1.y() + plane.C() * p1.z() + plane.D() ) / denominator;
        ( *normalizedDistFromP1 ) = u;
        if ( u > 0.0 && u < 1.0 )
        {
            return ( p1 + u * v );
        }
        else
        {
            if ( u >= 1.0 )
            {
                return p2;
            }
            else
            {
                return p1;
            }
        }
    }
    else
    {
        return p1;
    }
}

//--------------------------------------------------------------------------------------------------
/// Based on description and implementation from Paul Bourke:
///
///   http://paulbourke.net/geometry/polygonise/
///
/// Note that the element is turned inside-out compared to what we use elsewhere in caf/ResInsight
/// So the winding of all the sides are opposite.
///      4-----4------5
///     /|           /|         k         POS_I = 0
///    7 8          5 9         |         NEG_I = 1
///   /  |         /  |         |         POS_J = 2
///  7------6-----6   |         |         NEG_J = 3
///  |   0-----0--|---1         *------i  POS_K = 4
/// 11  /        10  /         /          NEG_K = 5
///  | 3          | 1         /           NO_FACE = 6
///  |/           |/         j
///  3------2-----2
///
// The cellFaceForEachTriangleEdge refer to the edge after the corresponding triangle vertex.
//--------------------------------------------------------------------------------------------------
int HexGridIntersectionTools::planeHexIntersectionMC( const cvf::Plane&    plane,
                                                      const cvf::Vec3d     cell[8],
                                                      const size_t         hexCornersIds[8],
                                                      std::vector<ClipVx>* triangleVxes,
                                                      std::vector<int>*    cellFaceForEachTriangleEdge )
{
    // clang-format off

    static const cvf::uint cubeIdxToCutEdgeBitfield[256] =
    {
        0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
        0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
        0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
        0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
        0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
        0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
        0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
        0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
        0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
        0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
        0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
        0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
        0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
        0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
        0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
        0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
        0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
        0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
        0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
        0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
        0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
        0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
        0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
        0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
        0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
        0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
        0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
        0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
        0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
        0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
        0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
        0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
    };

    // clang-format on

    static const int cubeIdxToTriangleIndices[256][16] =
        { { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
          { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },
          { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },
          { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 },
          { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },
          { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },
          { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },
          { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 },
          { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },
          { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 },
          { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
          { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 },
          { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 },
          { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },
          { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 },
          { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },
          { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },
          { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
          { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 },
          { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
          { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },
          { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 },
          { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },
          { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
          { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 },
          { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },
          { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
          { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },
          { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 },
          { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },
          { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
          { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },
          { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },
          { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
          { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },
          { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 },
          { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
          { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 },
          { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },
          { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 },
          { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 },
          { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },
          { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 },
          { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 },
          { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },
          { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 },
          { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },
          { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 },
          { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 },
          { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },
          { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },
          { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },
          { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 },
          { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
          { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },
          { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },
          { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 },
          { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },
          { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 },
          { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 },
          { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 },
          { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },
          { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },
          { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 },
          { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },
          { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },
          { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 },
          { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },
          { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 },
          { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },
          { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 },
          { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },
          { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },
          { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 },
          { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 },
          { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },
          { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 },
          { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },
          { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 },
          { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 },
          { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 },
          { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },
          { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 },
          { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },
          { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },
          { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 },
          { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },
          { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },
          { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 },
          { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },
          { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 },
          { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },
          { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 },
          { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },
          { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 },
          { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },
          { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 },
          { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 },
          { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 },
          { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },
          { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 },
          { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },
          { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 },
          { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },
          { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 },
          { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },
          { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 },
          { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },
          { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 },
          { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },
          { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 },
          { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },
          { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },
          { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 },
          { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 },
          { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
          { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };

    static const int edgeTable[12][2] =
        { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 }, { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } };

    int cubeIndex = 0;
    if ( plane.distanceSquared( cell[0] ) < 0 ) cubeIndex |= 1;
    if ( plane.distanceSquared( cell[1] ) < 0 ) cubeIndex |= 2;
    if ( plane.distanceSquared( cell[2] ) < 0 ) cubeIndex |= 4;
    if ( plane.distanceSquared( cell[3] ) < 0 ) cubeIndex |= 8;
    if ( plane.distanceSquared( cell[4] ) < 0 ) cubeIndex |= 16;
    if ( plane.distanceSquared( cell[5] ) < 0 ) cubeIndex |= 32;
    if ( plane.distanceSquared( cell[6] ) < 0 ) cubeIndex |= 64;
    if ( plane.distanceSquared( cell[7] ) < 0 ) cubeIndex |= 128;

    if ( cubeIdxToCutEdgeBitfield[cubeIndex] == 0 )
    {
        return 0;
    }

    cvf::Vec3d edgeIntersections[12];
    double     normDistAlongEdge[12]{};

    // Compute vertex coordinates on the edges where we have intersections
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 1 )
        edgeIntersections[0] = planeLineIntersectionForMC( plane, cell[0], cell[1], &normDistAlongEdge[0] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 2 )
        edgeIntersections[1] = planeLineIntersectionForMC( plane, cell[1], cell[2], &normDistAlongEdge[1] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 4 )
        edgeIntersections[2] = planeLineIntersectionForMC( plane, cell[2], cell[3], &normDistAlongEdge[2] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 8 )
        edgeIntersections[3] = planeLineIntersectionForMC( plane, cell[3], cell[0], &normDistAlongEdge[3] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 16 )
        edgeIntersections[4] = planeLineIntersectionForMC( plane, cell[4], cell[5], &normDistAlongEdge[4] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 32 )
        edgeIntersections[5] = planeLineIntersectionForMC( plane, cell[5], cell[6], &normDistAlongEdge[5] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 64 )
        edgeIntersections[6] = planeLineIntersectionForMC( plane, cell[6], cell[7], &normDistAlongEdge[6] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 128 )
        edgeIntersections[7] = planeLineIntersectionForMC( plane, cell[7], cell[4], &normDistAlongEdge[7] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 256 )
        edgeIntersections[8] = planeLineIntersectionForMC( plane, cell[0], cell[4], &normDistAlongEdge[8] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 512 )
        edgeIntersections[9] = planeLineIntersectionForMC( plane, cell[1], cell[5], &normDistAlongEdge[9] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 1024 )
        edgeIntersections[10] = planeLineIntersectionForMC( plane, cell[2], cell[6], &normDistAlongEdge[10] );
    if ( cubeIdxToCutEdgeBitfield[cubeIndex] & 2048 )
        edgeIntersections[11] = planeLineIntersectionForMC( plane, cell[3], cell[7], &normDistAlongEdge[11] );

    // Create the triangles

    const int* triangleIndicesToCubeEdges = cubeIdxToTriangleIndices[cubeIndex];
    cvf::uint  triangleVxIdx              = 0;

    int cubeEdgeIdx = triangleIndicesToCubeEdges[triangleVxIdx];
    while ( cubeEdgeIdx != -1 )
    {
        ClipVx cvx;
        cvx.vx                  = edgeIntersections[cubeEdgeIdx];
        cvx.normDistFromEdgeVx1 = normDistAlongEdge[cubeEdgeIdx];
        cvx.clippedEdgeVx1Id    = hexCornersIds[edgeTable[cubeEdgeIdx][0]];
        cvx.clippedEdgeVx2Id    = hexCornersIds[edgeTable[cubeEdgeIdx][1]];

        ( *triangleVxes ).push_back( cvx );
        ++triangleVxIdx;

        cubeEdgeIdx = triangleIndicesToCubeEdges[triangleVxIdx];
    }

    cvf::uint triangleCount = triangleVxIdx / 3;

    static const int edgeEdgeCutsToCellFace[12][12] = {
        // 0  1  2  3  4  5  6  7  8  9 10 11
        { 6, 5, 5, 5, 3, 6, 6, 6, 3, 3, 6, 6 }, // 0
        { 5, 6, 5, 5, 6, 0, 6, 6, 6, 0, 0, 6 }, // 1      POS_I = 0
        { 5, 5, 6, 5, 6, 6, 2, 6, 6, 6, 2, 2 }, // 2      NEG_I = 1
        { 5, 5, 5, 6, 6, 6, 6, 1, 1, 6, 6, 1 }, // 3      POS_J = 2
        { 3, 6, 6, 6, 6, 4, 4, 4, 3, 3, 6, 6 }, // 4      NEG_J = 3
        { 6, 0, 6, 6, 4, 6, 4, 4, 6, 0, 0, 6 }, // 5      POS_K = 4
        { 6, 6, 2, 6, 4, 4, 6, 4, 6, 6, 2, 2 }, // 6      NEG_K = 5
        { 6, 6, 6, 1, 4, 4, 4, 6, 1, 6, 6, 1 }, // 7      NO_FACE = 6
        { 3, 6, 6, 1, 3, 6, 6, 1, 6, 3, 6, 1 }, // 8
        { 3, 0, 6, 6, 3, 0, 6, 6, 3, 6, 0, 6 }, // 9
        { 6, 0, 2, 6, 6, 0, 2, 6, 6, 0, 6, 2 }, // 10
        { 6, 6, 2, 1, 6, 6, 2, 1, 1, 6, 2, 6 } // 11
    };

    ( *cellFaceForEachTriangleEdge ).clear();
    ( *cellFaceForEachTriangleEdge ).resize( triangleVxIdx, 6 );

    for ( cvf::uint tIdx = 0; tIdx < triangleCount; ++tIdx )
    {
        cvf::uint triVxIdx = 3 * tIdx;

        int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx];
        int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1];
        int cubeEdgeIdx3 = triangleIndicesToCubeEdges[triVxIdx + 2];

        ( *cellFaceForEachTriangleEdge )[triVxIdx + 0] = edgeEdgeCutsToCellFace[cubeEdgeIdx1][cubeEdgeIdx2];
        ( *cellFaceForEachTriangleEdge )[triVxIdx + 1] = edgeEdgeCutsToCellFace[cubeEdgeIdx2][cubeEdgeIdx3];
        ( *cellFaceForEachTriangleEdge )[triVxIdx + 2] = edgeEdgeCutsToCellFace[cubeEdgeIdx3][cubeEdgeIdx1];
    }

#if 0
    // Calculate what triangle edges are representing the cut of a cell face
    // Do this by counting the times two specific cube edges are used for a triangle edge.
    // Internal edges will have a count of 2, while external edges only 1

    (*isTriEdgeCellContour).clear();
    (*isTriEdgeCellContour).resize(triangleVxIdx);
 

    int triangleEdgeCount[12][12] = {
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    };

    (*isTriEdgeCellContour).clear();
    (*isTriEdgeCellContour).resize(triangleVxIdx, false);

    for (cvf::uint tIdx = 0; tIdx < triangleCount; ++tIdx)
    {
        cvf::uint triVxIdx = 3 * tIdx;
        int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx];
        int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1];
        int cubeEdgeIdx3 = triangleIndicesToCubeEdges[triVxIdx + 2];

        cubeEdgeIdx1 < cubeEdgeIdx2 ? ++triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx2] : ++triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx1];
        cubeEdgeIdx2 < cubeEdgeIdx3 ? ++triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx3] : ++triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx2];
        cubeEdgeIdx3 < cubeEdgeIdx1 ? ++triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx1] : ++triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx3];
    }

    for (cvf::uint tIdx = 0; tIdx < triangleCount; ++tIdx)
    {
        cvf::uint triVxIdx = 3 * tIdx;

        int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx];
        int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1];
        int cubeEdgeIdx3 = triangleIndicesToCubeEdges[triVxIdx + 2];

        // We have a contour if the count is exactly 1.

        (*isTriEdgeCellContour)[triVxIdx + 0] = (1 == (cubeEdgeIdx1 < cubeEdgeIdx2 ? triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx2] : triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx1]));
        (*isTriEdgeCellContour)[triVxIdx + 1] = (1 == (cubeEdgeIdx2 < cubeEdgeIdx3 ? triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx3] : triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx2]));
        (*isTriEdgeCellContour)[triVxIdx + 2] = (1 == (cubeEdgeIdx3 < cubeEdgeIdx1 ? triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx1] : triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx3]));
    }

#endif
    return triangleCount;
}

//--------------------------------------------------------------------------------------------------
/// Based on description and implementation from Paul Bourke:
///
///   http://paulbourke.net/geometry/polygonise/
///
/// Note that the element is turned inside-out compared to what we use elsewhere in caf/ResInsight
/// So the winding of all the sides are opposite.
///      4-----4------5
///     /|           /|         k         POS_I = 0
///    7 8          5 9         |         NEG_I = 1
///   /  |         /  |         |         POS_J = 2
///  7------6-----6   |         |         NEG_J = 3
///  |   0-----0--|---1         *------i  POS_K = 4
/// 11  /        10  /         /          NEG_K = 5
///  | 3          | 1         /           NO_FACE = 6
///  |/           |/         j
///  3------2-----2
///
// The cellFaceForEachTriangleEdge refer to the edge after the corresponding triangle vertex.

/*
   Based on description and implementation from Paul Bourke:
   http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/

   Polygonise a tetrahedron given its vertices within a cube
   This is an alternative algorithm to polygonisegrid.
   It results in a smoother surface but more triangular facets.

                      + 0                                 + 0
                     /|\                                 /|\
                    / | \                               / | \
                   /  |  \                             /  |  \
                  /   |   \                           /   |   \
                 /    |    \                         /  2 |    \
                /     |     \                       / __--+_    \
               +-------------+ 1                 3 +--__    --_  \
              3 \     |     /                           ---__  --_\
                 \    |    /                                 ---__-\
                  \   |   /                                       --+ 1
                   \  |  /
                    \ | /
                     \|/                         2 is behind 1 and 3
                      + 2


   Build six tets from a cube to make sure the split direction is equal for opposite sides.
   Surface normals are pointing outward.

   See following comment is taken from http://www.iue.tuwien.ac.at/phd/wessner/node32.html
   The decompositions of a cube into five tetrahedra yields an orientation switch of two opposite diagonal face edges of
the cube. Due to this fact, the tessellation of one cube, as part of a larger cubic grid, forces a particular
tessellation of all neighboring cubes to guarantee a conformal mesh. This means that, if such five-decompositions cubes
are stacked together to a chain, the mesh of each cube must be rotated by an angle of 90 deg

   The tessellation makes sure opposite faces are divided along the same line
   See figure http://www.ics.uci.edu/~eppstein/projects/tetra/

   4, 5, 6, 0
   0, 1, 5, 6
   0, 2, 1, 6
   4, 6, 7, 0
   0, 7, 3, 6
   0, 3, 2, 6

   Introduces the additional diagonal edges in the Hex from 12 up to and including 18:
   0 2 // 12 NEG_K
   0 5 // 13 NEG_J
   1 6 // 14 POS_I
   3 6 // 15 POS_J
   0 7 // 16 NEG_I
   4 6 // 17 POS_K
   0 6 // 18 Internal Diagonal

///      4-----4------5
///     /|           /|         k         POS_I = 0
///    7 8   17     5 9         |         NEG_I = 1
///   /  |    13   /  |         |         POS_J = 2
///  7------6-----6 14|         |         NEG_J = 3
///  |16 0-----0--|---1         *------i  POS_K = 4
/// 11  /  15    10  /         /          NEG_K = 5
///  | 3    12    | 1         /           NO_FACE = 6
///  |/           |/         j
///  3------2-----2


*/
//--------------------------------------------------------------------------------------------------
int HexGridIntersectionTools::planeHexIntersectionMCTet( const cvf::Plane&    plane,
                                                         const cvf::Vec3d     cell[8],
                                                         const size_t         hexCornersIds[8],
                                                         std::vector<ClipVx>* triangleVxes,
                                                         std::vector<int>*    cellFaceForEachTriangleEdge )
{
    std::array<double, 8> cellCornerSqDistToPlane = {
        plane.distanceSquared( cell[0] ),
        plane.distanceSquared( cell[1] ),
        plane.distanceSquared( cell[2] ),
        plane.distanceSquared( cell[3] ),
        plane.distanceSquared( cell[4] ),
        plane.distanceSquared( cell[5] ),
        plane.distanceSquared( cell[6] ),
        plane.distanceSquared( cell[7] ),
    };

    int cubeIndex = 0;
    if ( cellCornerSqDistToPlane[0] < 0 ) cubeIndex |= 1;
    if ( cellCornerSqDistToPlane[1] < 0 ) cubeIndex |= 2;
    if ( cellCornerSqDistToPlane[2] < 0 ) cubeIndex |= 4;
    if ( cellCornerSqDistToPlane[3] < 0 ) cubeIndex |= 8;
    if ( cellCornerSqDistToPlane[4] < 0 ) cubeIndex |= 16;
    if ( cellCornerSqDistToPlane[5] < 0 ) cubeIndex |= 32;
    if ( cellCornerSqDistToPlane[6] < 0 ) cubeIndex |= 64;
    if ( cellCornerSqDistToPlane[7] < 0 ) cubeIndex |= 128;

    if ( cubeIndex == 0 || cubeIndex == 255 ) return 0;

    int tetCount = 0;
    tetCount += planeMcTetIntersection( plane,
                                        cell,
                                        hexCornersIds,
                                        cellCornerSqDistToPlane.data(),
                                        { 4, 5, 6, 0 },
                                        triangleVxes,
                                        cellFaceForEachTriangleEdge );
    tetCount += planeMcTetIntersection( plane,
                                        cell,
                                        hexCornersIds,
                                        cellCornerSqDistToPlane.data(),
                                        { 0, 1, 5, 6 },
                                        triangleVxes,
                                        cellFaceForEachTriangleEdge );
    tetCount += planeMcTetIntersection( plane,
                                        cell,
                                        hexCornersIds,
                                        cellCornerSqDistToPlane.data(),
                                        { 0, 2, 1, 6 },
                                        triangleVxes,
                                        cellFaceForEachTriangleEdge );
    tetCount += planeMcTetIntersection( plane,
                                        cell,
                                        hexCornersIds,
                                        cellCornerSqDistToPlane.data(),
                                        { 4, 6, 7, 0 },
                                        triangleVxes,
                                        cellFaceForEachTriangleEdge );
    tetCount += planeMcTetIntersection( plane,
                                        cell,
                                        hexCornersIds,
                                        cellCornerSqDistToPlane.data(),
                                        { 0, 7, 3, 6 },
                                        triangleVxes,
                                        cellFaceForEachTriangleEdge );
    tetCount += planeMcTetIntersection( plane,
                                        cell,
                                        hexCornersIds,
                                        cellCornerSqDistToPlane.data(),
                                        { 0, 3, 2, 6 },
                                        triangleVxes,
                                        cellFaceForEachTriangleEdge );

    return tetCount;
}

//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::uint HexGridIntersectionTools::planeMcTetIntersection( const cvf::Plane&         plane,
                                                            const cvf::Vec3d          hexCell[8],
                                                            const size_t              hexCornersIds[8],
                                                            const double              cornerDistToPlane[8],
                                                            const std::array<int, 4>& tetCell,
                                                            std::vector<ClipVx>*      triangleVxes,
                                                            std::vector<int>*         cellFaceForEachTriangleEdge )
{
    // clang-format off

    static const int edgeEdgeCutsToCellFace[19][19] = {
        // 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18                                        4--------------4---------------5
         { 6, 5, 5, 5, 3, 6, 6, 6, 3, 3, 6, 6, 5, 3, 6, 6, 6, 6, 6 }, // 0                               /|\__                       __//|
         { 5, 6, 5, 5, 6, 0, 6, 6, 6, 0, 0, 6, 5, 6, 0, 6, 6, 6, 6 }, // 1      POS_I = 0               / |   \___                 _/  / |
         { 5, 5, 6, 5, 6, 6, 2, 6, 6, 6, 2, 2, 5, 6, 6, 2, 6, 6, 6 }, // 2      NEG_I = 1              7  |       \__           __/   /  |             k       
         { 5, 5, 5, 6, 6, 6, 6, 1, 1, 6, 6, 1, 5, 6, 6, 6, 1, 6, 6 }, // 3      POS_J = 2             /   |          17___    _/     5   |             |       
         { 3, 6, 6, 6, 6, 4, 4, 4, 3, 3, 6, 6, 6, 3, 6, 6, 6, 4, 6 }, // 4      NEG_J = 3            /    8               \___      /    9             |       
         { 6, 0, 6, 6, 4, 6, 4, 4, 6, 0, 0, 6, 6, 6, 0, 6, 6, 4, 6 }, // 5      POS_K = 4           /     |             __/   \___ /     |             |       
         { 6, 6, 2, 6, 4, 4, 6, 4, 6, 6, 2, 2, 6, 6, 6, 2, 6, 4, 6 }, // 6      NEG_K = 5          7---------------6--------------6      |             *------i
         { 6, 6, 6, 1, 4, 4, 4, 6, 1, 6, 6, 1, 6, 6, 6, 6, 1, 4, 6 }, // 7      NO_FACE = 6        |\_    |         __13   ____/_/|\_    |            /        
         { 3, 6, 6, 1, 3, 6, 6, 1, 6, 3, 6, 1, 6, 3, 6, 6, 1, 6, 6 }, // 8                         |  16  |      __/  _18_/  __/  |  14  |           /         
         { 3, 0, 6, 6, 3, 0, 6, 6, 3, 6, 0, 6, 6, 3, 0, 6, 6, 6, 6 }, // 9                         |   \_ |   __/____/     _/     |   \_ |          j        
         { 6, 0, 2, 6, 6, 0, 2, 6, 6, 0, 6, 2, 6, 6, 0, 2, 6, 6, 6 }, // 10                        |     \|__/__/       __/       |     \|
         { 6, 6, 2, 1, 6, 6, 2, 1, 1, 6, 2, 6, 6, 6, 6, 2, 1, 6, 6 }, // 11                        |      0-----------_/----0-----|------1
         { 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, // 12                       11     / \__     __15          10     /     
         { 3, 6, 6, 6, 3, 6, 6, 6, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, // 13                        |    /     \_ _/               |    /      
         { 6, 0, 6, 6, 6, 0, 6, 6, 6, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6 }, // 14                        |   3      __/ \___            |   1       
         { 6, 6, 2, 6, 6, 6, 2, 6, 6, 6, 2, 2, 6, 6, 6, 6, 6, 6, 6 }, // 15                        |  /    __/        12__        |  /        
         { 6, 6, 6, 1, 6, 6, 6, 1, 1, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6 }, // 16                        | /  __/               \___    | /         
         { 6, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, // 17                        |/__/                      \___|/          
         { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }, // 18                        3---------------2--------------2
    };

    // clang-format on

    static const int cellCornerCellCornerToEdge[8][8] = {
        //     0   1   2   3   4   5   6   7
        { -1, 0, 12, 3, 8, 13, 18, 16 }, // 0
        { 0, -1, 1, -1, -1, 9, 14, -1 }, // 1
        { 12, 1, -1, 2, -1, -1, 10, -1 }, // 2
        { 3, -1, 2, -1, -1, -1, 15, 11 }, // 3
        { 8, -1, -1, -1, -1, 4, 17, 7 }, // 4
        { 13, 9, -1, -1, 4, -1, 5, -1 }, // 5
        { 18, 14, 10, 15, 17, 5, -1, 6 }, // 6
        { 16, -1, -1, 11, 7, -1, 6, -1 }, // 7
    };

    cvf::uint ntri = 0;

    int triindex = 0;
    if ( cornerDistToPlane[tetCell[0]] < 0 ) triindex |= 1;
    if ( cornerDistToPlane[tetCell[1]] < 0 ) triindex |= 2;
    if ( cornerDistToPlane[tetCell[2]] < 0 ) triindex |= 4;
    if ( cornerDistToPlane[tetCell[3]] < 0 ) triindex |= 8;

    auto clipEdgeFunc = [&]( int hexCornerIdx0, int hexCornerIdx1 ) {
        ClipVx cvx;
        cvx.vx =
            planeLineIntersectionForMC( plane, hexCell[hexCornerIdx0], hexCell[hexCornerIdx1], &cvx.normDistFromEdgeVx1 );
        cvx.clippedEdgeVx1Id = hexCornersIds[hexCornerIdx0];
        cvx.clippedEdgeVx2Id = hexCornersIds[hexCornerIdx1];
        return cvx;
    };

    auto addCellFaceStatusForTriangleEdges = [&]( int e11, int e12, int e21, int e22, int e31, int e32 ) {
        int cutEdge1 = cellCornerCellCornerToEdge[e11][e12];
        int cutEdge2 = cellCornerCellCornerToEdge[e21][e22];
        int cutEdge3 = cellCornerCellCornerToEdge[e31][e32];

        CVF_ASSERT( cutEdge1 >= 0 );
        CVF_ASSERT( cutEdge2 >= 0 );
        CVF_ASSERT( cutEdge3 >= 0 );

        cellFaceForEachTriangleEdge->emplace_back( edgeEdgeCutsToCellFace[cutEdge1][cutEdge2] );
        cellFaceForEachTriangleEdge->emplace_back( edgeEdgeCutsToCellFace[cutEdge2][cutEdge3] );
        cellFaceForEachTriangleEdge->emplace_back( edgeEdgeCutsToCellFace[cutEdge3][cutEdge1] );
    };

    switch ( triindex )
    {
        case 0x00:
        case 0x0F:
            break;
        case 0x0E:
        case 0x01:
        {
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[0], tetCell[1] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[0], tetCell[2] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[0], tetCell[3] ) );

            addCellFaceStatusForTriangleEdges( tetCell[0], tetCell[1], tetCell[0], tetCell[2], tetCell[0], tetCell[3] );
            ntri++;
        }
        break;
        case 0x0D:
        case 0x02:
        {
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[1], tetCell[0] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[1], tetCell[3] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[1], tetCell[2] ) );

            addCellFaceStatusForTriangleEdges( tetCell[1], tetCell[0], tetCell[1], tetCell[3], tetCell[1], tetCell[2] );
            ntri++;
        }
        break;
        case 0x0C:
        case 0x03:
        {
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[0], tetCell[3] ) );
            ClipVx vx1 = clipEdgeFunc( tetCell[0], tetCell[2] );
            triangleVxes->push_back( vx1 );
            ClipVx vx2 = clipEdgeFunc( tetCell[1], tetCell[3] );
            triangleVxes->push_back( vx2 );

            addCellFaceStatusForTriangleEdges( tetCell[0], tetCell[3], tetCell[0], tetCell[2], tetCell[1], tetCell[3] );

            ntri++;

            triangleVxes->push_back( vx2 );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[1], tetCell[2] ) );
            triangleVxes->push_back( vx1 );

            addCellFaceStatusForTriangleEdges( tetCell[1], tetCell[3], tetCell[1], tetCell[2], tetCell[0], tetCell[2] );
            ntri++;
        }
        break;
        case 0x0B:
        case 0x04:
        {
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[2], tetCell[0] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[2], tetCell[1] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[2], tetCell[3] ) );

            addCellFaceStatusForTriangleEdges( tetCell[2], tetCell[0], tetCell[2], tetCell[1], tetCell[2], tetCell[3] );
            ntri++;
        }
        break;
        case 0x0A:
        case 0x05:
        {
            ClipVx vx0 = clipEdgeFunc( tetCell[0], tetCell[1] );
            triangleVxes->push_back( vx0 );
            ClipVx vx1 = clipEdgeFunc( tetCell[2], tetCell[3] );
            triangleVxes->push_back( vx1 );
            ClipVx vx2 = clipEdgeFunc( tetCell[0], tetCell[3] );
            triangleVxes->push_back( vx2 );

            addCellFaceStatusForTriangleEdges( tetCell[0], tetCell[1], tetCell[2], tetCell[3], tetCell[0], tetCell[3] );
            ntri++;

            triangleVxes->push_back( vx0 );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[1], tetCell[2] ) );
            triangleVxes->push_back( vx1 );

            addCellFaceStatusForTriangleEdges( tetCell[0], tetCell[1], tetCell[1], tetCell[2], tetCell[2], tetCell[3] );

            ntri++;
        }
        break;
        case 0x09:
        case 0x06:
        {
            ClipVx vx0 = clipEdgeFunc( tetCell[0], tetCell[1] );
            triangleVxes->push_back( vx0 );
            ClipVx vx1 = clipEdgeFunc( tetCell[1], tetCell[3] );
            triangleVxes->push_back( vx1 );
            ClipVx vx2 = clipEdgeFunc( tetCell[2], tetCell[3] );
            triangleVxes->push_back( vx2 );

            addCellFaceStatusForTriangleEdges( tetCell[0], tetCell[1], tetCell[1], tetCell[3], tetCell[2], tetCell[3] );

            ntri++;

            triangleVxes->push_back( vx0 );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[0], tetCell[2] ) );
            triangleVxes->push_back( vx2 );

            addCellFaceStatusForTriangleEdges( tetCell[0], tetCell[1], tetCell[0], tetCell[2], tetCell[2], tetCell[3] );

            ntri++;
        }
        break;
        case 0x07:
        case 0x08:
        {
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[3], tetCell[0] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[3], tetCell[2] ) );
            triangleVxes->emplace_back( clipEdgeFunc( tetCell[3], tetCell[1] ) );

            addCellFaceStatusForTriangleEdges( tetCell[3], tetCell[0], tetCell[3], tetCell[2], tetCell[3], tetCell[1] );

            ntri++;
        }
        break;
    }

    return ntri;
}

} // namespace caf

// clang-format on
} //namespace external
