2020-01-14 02:34:27 -06:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright (C) 2020 Equinor ASA
|
|
|
|
//
|
|
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
//
|
|
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
|
|
// for more details.
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "RigCellFaceGeometryTools.h"
|
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
#include "RigActiveCellInfo.h"
|
2020-01-14 02:34:27 -06:00
|
|
|
#include "RigCell.h"
|
|
|
|
#include "RigMainGrid.h"
|
2020-01-15 01:45:40 -06:00
|
|
|
#include "RigNncConnection.h"
|
2020-01-14 02:34:27 -06:00
|
|
|
|
|
|
|
#include "cvfGeometryTools.h"
|
|
|
|
|
2020-01-15 01:45:40 -06:00
|
|
|
#include "cafAssert.h"
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
#include <omp.h>
|
|
|
|
|
2020-01-14 02:34:27 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
cvf::StructGridInterface::FaceType
|
|
|
|
RigCellFaceGeometryTools::calculateCellFaceOverlap( const RigCell& c1,
|
|
|
|
const RigCell& c2,
|
|
|
|
const RigMainGrid& mainGrid,
|
|
|
|
std::vector<size_t>* connectionPolygon,
|
|
|
|
std::vector<cvf::Vec3d>* connectionIntersections )
|
|
|
|
{
|
|
|
|
// Try to find the shared face
|
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
bool isPossibleNeighborInDirection[6] = { true, true, true, true, true, true };
|
2020-01-14 02:34:27 -06:00
|
|
|
|
|
|
|
if ( c1.hostGrid() == c2.hostGrid() )
|
|
|
|
{
|
|
|
|
char hasNeighbourInAnyDirection = 0;
|
|
|
|
|
|
|
|
size_t i1, j1, k1;
|
|
|
|
c1.hostGrid()->ijkFromCellIndex( c1.gridLocalCellIndex(), &i1, &j1, &k1 );
|
|
|
|
size_t i2, j2, k2;
|
|
|
|
c2.hostGrid()->ijkFromCellIndex( c2.gridLocalCellIndex(), &i2, &j2, &k2 );
|
|
|
|
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] = ( ( i1 + 1 ) == i2 );
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] = ( ( i2 + 1 ) == i1 );
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] = ( ( j1 + 1 ) == j2 );
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] = ( ( j2 + 1 ) == j1 );
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] = ( ( k1 + 1 ) == k2 );
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K] = ( ( k2 + 1 ) == k1 );
|
|
|
|
|
|
|
|
hasNeighbourInAnyDirection = isPossibleNeighborInDirection[cvf::StructGridInterface::POS_I] +
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_I] +
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_J] +
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_J] +
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::POS_K] +
|
|
|
|
isPossibleNeighborInDirection[cvf::StructGridInterface::NEG_K];
|
|
|
|
|
|
|
|
// If cell 2 is not adjancent with respect to any of the six ijk directions,
|
|
|
|
// assume that we have no overlapping area.
|
|
|
|
|
|
|
|
if ( !hasNeighbourInAnyDirection )
|
|
|
|
{
|
|
|
|
// Add to search map
|
|
|
|
// m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c1GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx);
|
|
|
|
// m_cellIdxToFaceToConnectionIdxMap[m_connections[cnIdx].m_c2GlobIdx][cvf::StructGridInterface::NO_FACE].push_back(cnIdx);
|
|
|
|
|
|
|
|
// cvf::Trace::show("NNC: No direct neighbors : C1: " + cvf::String((int)m_connections[cnIdx].m_c1GlobIdx) +
|
|
|
|
// " C2: " + cvf::String((int)m_connections[cnIdx].m_c2GlobIdx));
|
|
|
|
return cvf::StructGridInterface::NO_FACE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( unsigned char fIdx = 0; fIdx < 6; ++fIdx )
|
|
|
|
{
|
|
|
|
if ( !isPossibleNeighborInDirection[fIdx] )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate connection polygon
|
|
|
|
|
|
|
|
std::vector<size_t> polygon;
|
|
|
|
std::vector<cvf::Vec3d> intersections;
|
|
|
|
std::array<size_t, 4> face1;
|
|
|
|
std::array<size_t, 4> face2;
|
|
|
|
c1.faceIndices( ( cvf::StructGridInterface::FaceType )( fIdx ), &face1 );
|
|
|
|
c2.faceIndices( cvf::StructGridInterface::oppositeFace( ( cvf::StructGridInterface::FaceType )( fIdx ) ), &face2 );
|
|
|
|
|
|
|
|
bool foundOverlap =
|
|
|
|
cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads( &polygon,
|
|
|
|
&intersections,
|
|
|
|
(cvf::EdgeIntersectStorage<size_t>*)nullptr,
|
|
|
|
cvf::wrapArrayConst( &mainGrid.nodes() ),
|
|
|
|
face1.data(),
|
|
|
|
face2.data(),
|
|
|
|
1e-6 );
|
|
|
|
|
|
|
|
if ( foundOverlap )
|
|
|
|
{
|
|
|
|
if ( connectionPolygon ) ( *connectionPolygon ) = polygon;
|
|
|
|
if ( connectionIntersections ) ( *connectionIntersections ) = intersections;
|
|
|
|
return ( cvf::StructGridInterface::FaceType )( fIdx );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cvf::StructGridInterface::NO_FACE;
|
|
|
|
}
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
void assignThreadConnections( std::set<std::pair<size_t, size_t>>& existingPairs,
|
|
|
|
RigConnectionContainer& allConnections,
|
|
|
|
RigConnectionContainer& threadConnections )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
for ( size_t i = 0; i < threadConnections.size(); ++i )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
#pragma omp critical
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
RigConnection connection = threadConnections[i];
|
|
|
|
auto it = existingPairs.emplace( connection.m_c1GlobIdx, connection.m_c2GlobIdx );
|
|
|
|
if ( it.second )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
allConnections.push_back( connection );
|
2020-01-15 01:45:40 -06:00
|
|
|
}
|
|
|
|
}
|
2020-05-12 11:19:27 -05:00
|
|
|
}
|
|
|
|
threadConnections.clear();
|
|
|
|
}
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
RigConnectionContainer RigCellFaceGeometryTools::computeOtherNncs( const RigMainGrid* mainGrid,
|
|
|
|
const RigConnectionContainer& nativeConnections,
|
|
|
|
const RigActiveCellInfo* activeCellInfo )
|
|
|
|
{
|
|
|
|
// Compute Non-Neighbor Connections (NNC) not reported by Eclipse. NNCs with zero transmissibility are not reported
|
|
|
|
// by Eclipse. Use faults as basis for subset of cells to find NNC connection for. The imported connections from
|
|
|
|
// Eclipse are located at the beginning of the connections vector.
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
std::set<std::pair<size_t, size_t>> nativeCellPairs;
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
for ( size_t i = 0; i < nativeConnections.size(); ++i )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
RigConnection c = nativeConnections[i];
|
|
|
|
nativeCellPairs.emplace( c.m_c1GlobIdx, c.m_c2GlobIdx );
|
2020-01-15 01:45:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( nativeConnections.size() != nativeCellPairs.size() )
|
|
|
|
{
|
|
|
|
QString message = QString( "Nnc connection imported from Eclipse are not unique\nNNC count : %1\nUnique : %2" )
|
|
|
|
.arg( nativeConnections.size() )
|
|
|
|
.arg( nativeCellPairs.size() );
|
|
|
|
qDebug() << message;
|
|
|
|
}
|
|
|
|
|
|
|
|
const cvf::Collection<RigFault>& faults = mainGrid->faults();
|
2020-02-03 07:49:07 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
std::set<std::pair<size_t, size_t>> existingPairs;
|
|
|
|
RigConnectionContainer otherConnections;
|
|
|
|
|
|
|
|
for ( int faultIdx = 0; faultIdx < (int)faults.size(); faultIdx++ )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
|
|
|
const RigFault* fault = faults.at( faultIdx );
|
|
|
|
|
|
|
|
const std::vector<RigFault::FaultFace>& faultFaces = fault->faultFaces();
|
2020-01-27 01:57:32 -06:00
|
|
|
|
2020-05-13 03:57:30 -05:00
|
|
|
// Build a vector of active face indices so we don't have to have this check inside the parallel loop.
|
|
|
|
// This makes the load balancing much better in the loop.
|
|
|
|
std::vector<size_t> activeFaceIndices;
|
|
|
|
activeFaceIndices.reserve( faultFaces.size() );
|
|
|
|
for ( size_t faceIdx = 0; faceIdx < faultFaces.size(); ++faceIdx )
|
|
|
|
{
|
|
|
|
const RigFault::FaultFace& f = faultFaces[faceIdx];
|
|
|
|
|
|
|
|
bool atLeastOneCellActive = true;
|
|
|
|
if ( activeCellInfo && activeCellInfo->reservoirActiveCellCount() > 0u )
|
|
|
|
{
|
|
|
|
atLeastOneCellActive = activeCellInfo->isActive( f.m_nativeReservoirCellIndex ) ||
|
|
|
|
activeCellInfo->isActive( f.m_oppositeReservoirCellIndex );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( atLeastOneCellActive ) activeFaceIndices.push_back( faceIdx );
|
|
|
|
}
|
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
#pragma omp parallel
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
RigConnectionContainer threadConnections;
|
2020-05-13 03:40:39 -05:00
|
|
|
#pragma omp for schedule( guided )
|
2020-05-13 03:57:30 -05:00
|
|
|
for ( int activeFaceIdx = 0; activeFaceIdx < static_cast<int>( activeFaceIndices.size() ); activeFaceIdx++ )
|
2020-02-24 08:49:09 -06:00
|
|
|
{
|
2020-05-13 03:57:30 -05:00
|
|
|
size_t faceIdx = activeFaceIndices[activeFaceIdx];
|
|
|
|
const RigFault::FaultFace& f = faultFaces[faceIdx];
|
|
|
|
|
|
|
|
RigConnectionContainer faceConnections = extractConnectionsForFace( f, mainGrid, nativeCellPairs );
|
|
|
|
threadConnections.insert( faceConnections );
|
2020-02-24 08:49:09 -06:00
|
|
|
}
|
2020-05-12 11:19:27 -05:00
|
|
|
// Merge together connections per thread
|
|
|
|
assignThreadConnections( existingPairs, otherConnections, threadConnections );
|
|
|
|
} // end parallel region
|
|
|
|
}
|
|
|
|
|
|
|
|
return otherConnections;
|
|
|
|
}
|
2020-02-24 08:49:09 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
RigConnectionContainer
|
|
|
|
RigCellFaceGeometryTools::extractConnectionsForFace( const RigFault::FaultFace& face,
|
|
|
|
const RigMainGrid* mainGrid,
|
|
|
|
const std::set<std::pair<size_t, size_t>>& nativeCellPairs )
|
|
|
|
{
|
|
|
|
RigConnectionContainer faceConnections;
|
|
|
|
size_t sourceReservoirCellIndex = face.m_nativeReservoirCellIndex;
|
|
|
|
cvf::StructGridInterface::FaceType sourceCellFace = face.m_nativeFace;
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
if ( sourceReservoirCellIndex >= mainGrid->cellCount() )
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
const std::vector<cvf::Vec3d>& mainGridNodes = mainGrid->nodes();
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
cvf::BoundingBox bb;
|
|
|
|
std::array<size_t, 4> sourceFaceIndices;
|
|
|
|
mainGrid->globalCellArray()[sourceReservoirCellIndex].faceIndices( sourceCellFace, &sourceFaceIndices );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
bb.add( mainGridNodes[sourceFaceIndices[0]] );
|
|
|
|
bb.add( mainGridNodes[sourceFaceIndices[1]] );
|
|
|
|
bb.add( mainGridNodes[sourceFaceIndices[2]] );
|
|
|
|
bb.add( mainGridNodes[sourceFaceIndices[3]] );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
std::vector<size_t> closeCells;
|
|
|
|
mainGrid->findIntersectingCells( bb, &closeCells );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
cvf::StructGridInterface::FaceType candidateFace = cvf::StructGridInterface::oppositeFace( sourceCellFace );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
size_t neighborCellIndex = std::numeric_limits<size_t>::max();
|
|
|
|
size_t ni = std::numeric_limits<size_t>::max();
|
|
|
|
size_t nj = std::numeric_limits<size_t>::max();
|
|
|
|
size_t nk = std::numeric_limits<size_t>::max();
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
size_t j;
|
|
|
|
size_t k;
|
|
|
|
mainGrid->ijkFromCellIndex( sourceReservoirCellIndex, &i, &j, &k );
|
|
|
|
|
|
|
|
mainGrid->neighborIJKAtCellFace( i, j, k, sourceCellFace, &ni, &nj, &nk );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
if ( mainGrid->isCellValid( ni, nj, nk ) )
|
|
|
|
{
|
|
|
|
neighborCellIndex = mainGrid->cellIndexFromIJK( ni, nj, nk );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( size_t candidateCellIndex : closeCells )
|
|
|
|
{
|
|
|
|
if ( candidateCellIndex == sourceReservoirCellIndex )
|
|
|
|
{
|
|
|
|
// Exclude cellIndex for source cell
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( candidateCellIndex == neighborCellIndex )
|
|
|
|
{
|
|
|
|
// Exclude direct neighbor
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( candidateCellIndex >= mainGrid->cellCount() )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( neighborCellIndex != std::numeric_limits<size_t>::max() )
|
|
|
|
{
|
|
|
|
// Find target IJK index based on source cell and cell face
|
|
|
|
// Exclude cells not matching destination target index
|
|
|
|
|
|
|
|
size_t ci = std::numeric_limits<size_t>::max();
|
|
|
|
size_t cj = std::numeric_limits<size_t>::max();
|
|
|
|
size_t ck = std::numeric_limits<size_t>::max();
|
|
|
|
mainGrid->ijkFromCellIndex( candidateCellIndex, &ci, &cj, &ck );
|
|
|
|
|
|
|
|
auto gridAxis = cvf::StructGridInterface::gridAxisFromFace( sourceCellFace );
|
|
|
|
if ( gridAxis == cvf::StructGridInterface::GridAxisType::AXIS_I )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
2020-05-12 11:19:27 -05:00
|
|
|
if ( ni != ci )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-05-12 11:19:27 -05:00
|
|
|
}
|
|
|
|
else if ( gridAxis == cvf::StructGridInterface::GridAxisType::AXIS_J )
|
|
|
|
{
|
|
|
|
if ( nj != cj )
|
2020-01-15 01:45:40 -06:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-05-12 11:19:27 -05:00
|
|
|
}
|
|
|
|
else if ( gridAxis == cvf::StructGridInterface::GridAxisType::AXIS_K )
|
|
|
|
{
|
|
|
|
if ( nk != ck )
|
2020-02-24 08:49:09 -06:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-05-12 11:19:27 -05:00
|
|
|
}
|
|
|
|
}
|
2020-02-24 08:49:09 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
std::pair<size_t, size_t> candidate( sourceReservoirCellIndex, candidateCellIndex );
|
|
|
|
|
|
|
|
if ( nativeCellPairs.count( candidate ) > 0 )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
std::vector<size_t> polygon;
|
|
|
|
std::vector<cvf::Vec3d> intersections;
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
std::array<size_t, 4> candidateFaceIndices;
|
|
|
|
mainGrid->globalCellArray()[candidateCellIndex].faceIndices( candidateFace, &candidateFaceIndices );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
bool foundOverlap =
|
|
|
|
cvf::GeometryTools::calculateOverlapPolygonOfTwoQuads( &polygon,
|
|
|
|
&intersections,
|
|
|
|
(cvf::EdgeIntersectStorage<size_t>*)nullptr,
|
|
|
|
cvf::wrapArrayConst( &mainGridNodes ),
|
|
|
|
sourceFaceIndices.data(),
|
|
|
|
candidateFaceIndices.data(),
|
|
|
|
1e-6 );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
if ( foundOverlap )
|
|
|
|
{
|
|
|
|
RigConnection conn;
|
|
|
|
conn.m_c1GlobIdx = sourceReservoirCellIndex;
|
|
|
|
conn.m_c2GlobIdx = candidateCellIndex;
|
|
|
|
conn.m_c1Face = sourceCellFace;
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
conn.m_polygon = RigCellFaceGeometryTools::extractPolygon( mainGridNodes, polygon, intersections );
|
2020-01-15 01:45:40 -06:00
|
|
|
|
2020-05-12 11:19:27 -05:00
|
|
|
faceConnections.push_back( conn );
|
2020-01-15 01:45:40 -06:00
|
|
|
}
|
|
|
|
}
|
2020-05-12 11:19:27 -05:00
|
|
|
return faceConnections;
|
2020-01-15 01:45:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::vector<cvf::Vec3d> RigCellFaceGeometryTools::extractPolygon( const std::vector<cvf::Vec3d>& nativeNodes,
|
|
|
|
const std::vector<size_t>& connectionPolygon,
|
|
|
|
const std::vector<cvf::Vec3d>& connectionIntersections )
|
|
|
|
{
|
|
|
|
std::vector<cvf::Vec3d> allPolygonNodes;
|
|
|
|
|
|
|
|
for ( size_t polygonIndex : connectionPolygon )
|
|
|
|
{
|
|
|
|
if ( polygonIndex < nativeNodes.size() )
|
|
|
|
allPolygonNodes.push_back( nativeNodes[polygonIndex] );
|
|
|
|
else
|
|
|
|
allPolygonNodes.push_back( connectionIntersections[polygonIndex - nativeNodes.size()] );
|
|
|
|
}
|
|
|
|
|
|
|
|
return allPolygonNodes;
|
|
|
|
}
|