Exemple #1
0
void
SVLocusSet::
getIntersectingEdgeNodes(
    const LocusIndexType inputLocusIndex,
    const NodeIndexType inputRemoteNodeIndex,
    const EdgeMapType& remoteIntersectNodeToLocalNodeMap,
    const LocusSetIndexerType& remoteIntersectNodes,
    std::vector<EdgeInfoType>& edges) const
{
    typedef EdgeMapType::const_iterator rliter_t;
    typedef std::pair<rliter_t,rliter_t> rlmap_range_t;

    edges.clear();

    // find all nodes, from the remoteIntersectNodes set, which intersect this function's input node:
    //
    // for this application, inputLocus is an input set isolated from the rest of the graph, so nodes
    // intersected in the inputLocus are filtered out
    //
    std::set<NodeAddressType> edgeIntersectRemoteTemp;
    getNodeIntersectCore(inputLocusIndex,inputRemoteNodeIndex,remoteIntersectNodes,inputLocusIndex,edgeIntersectRemoteTemp);

    for (const NodeAddressType& remoteIsectAddy : edgeIntersectRemoteTemp)
    {
        // find what local nodes the remote nodes trace back to:
        const rlmap_range_t remoteIsectRange(remoteIntersectNodeToLocalNodeMap.equal_range(remoteIsectAddy));
        assert(remoteIsectRange.first != remoteIntersectNodeToLocalNodeMap.end());
        for (rliter_t riter(remoteIsectRange.first); riter != remoteIsectRange.second; ++riter)
        {
            const NodeAddressType localIntersectAddy(std::make_pair(remoteIsectAddy.first,riter->second));
            edges.push_back(std::make_pair(localIntersectAddy,remoteIsectAddy.second));
        }
    }
}
Exemple #2
0
void
SVLocusSet::
getNodeMergeableIntersect(
    const LocusIndexType inputLocusIndex,
    const NodeIndexType inputNodeIndex,
    const bool isInputLocusMoved,
    std::set<NodeAddressType>& mergeIntersectNodes) const
{
    //
    // TODO: There's room for significant optimization of these methods. The improvements are not trivial,
    //   but they would allow us to filter fewer nodes from being merged when node intersection counts become large.
    //

    //
    // There are two ways sets of mergeable nodes can occur:
    //
    // (1) There is a set of nodes which overlap with both input node and one
    // of the remote nodes that the input points to (ie they have a shared edge).
    // When totaled together, the edge count of this set + the inputNode edge
    // exceeds minMergeEdgeCount.
    //
    // (2) The input node either contains an edge which is greater than minMergeEdgeCount
    // or will contain such an edge due to (1), in this case the input node can be merged
    // with a locally overlapping node which also contains an edge which is greater than
    // minMergeEdgeCount. Note that in case (2) remote node intersection is not required.
    //

    const NodeAddressType inputAddy(std::make_pair(inputLocusIndex,inputNodeIndex));
    const SVLocusNode& inputNode(getNode(inputAddy));

#ifdef DEBUG_SVL
    static const std::string logtag("SVLocusSet::getNodeMergableIntersect");
    log_os << logtag << " inputNode: " << inputAddy << " " << inputNode;
    checkState();
#endif

    // reuse this intersectNodes as a temporary throughout the methods below
    std::set<NodeAddressType> intersectNodes;

    //
    // build a new index, which contains, for all nodes x which intersect the input, an
    // enumeration of the remote nodes Y connected by edges to node x (remoteIntersectNodes)
    // and a map for each node y \in Y pointing back to node x (remoteIntersectNodeToLocalNodeMap)
    //
    LocusSetIndexerType remoteIntersectNodes(*this);
    EdgeMapType remoteIntersectNodeToLocalNodeMap;

    // nodes which intersect the input and have already been certified as signal:
    std::set<NodeAddressType> signalIntersectNodes;
    {
        // get a standard intersection of the input node:
        getNodeIntersect(inputLocusIndex, inputNodeIndex, intersectNodes);

        //
        // 1. build the new remoteIntersectNodes/remoteIntersectNodeToLocalNodeMap index
        //
        for (const NodeAddressType& intersectAddy : intersectNodes)
        {
            const SVLocusNode& intersectNode(getNode(intersectAddy));

            // get the remotes of each node which intersect with the query node,
            // place these in remoteIntersectNodes
            const SVLocusEdgeManager edgeMap(intersectNode.getEdgeManager());
            for (const SVLocusEdgesType::value_type& intersectEdge : edgeMap.getMap())
            {
                // build remote <-> local indexing structures:
                NodeAddressType remoteAddy(std::make_pair(intersectAddy.first,intersectEdge.first));
                remoteIntersectNodes.data().insert(remoteAddy);
                remoteIntersectNodeToLocalNodeMap.insert(std::make_pair(remoteAddy,intersectAddy.second));
            }
        }

#ifdef DEBUG_SVL
        log_os << logtag << " remoteIntersectNodes.size(): " << remoteIntersectNodes.data().size() << "\n";
        for (const NodeAddressType& addy : remoteIntersectNodes.data())
        {
            log_os << logtag << "\tremoteIntersectNode: " << addy << " " << getNode(addy);
        }
#endif

        //
        // 2. get the signal node set:
        //
        // Note that the signal node search is not transitive b/c we have required all signal nodes
        // in the graph to have merged already.
        //
        for (const NodeAddressType& intersectAddy : intersectNodes)
        {
            if (! isNoiseNode(intersectAddy))
            {
                signalIntersectNodes.insert(intersectAddy);
            }
        }

#ifdef DEBUG_SVL
        log_os << logtag << " signalIntersect.size(): " << signalIntersectNodes.size() << "\n";
        for (const NodeAddressType& addy : signalIntersectNodes)
        {
            log_os << logtag << "\tsignalIntersectNode: " << addy << " " << getNode(addy);
        }
#endif
    }

    //
    // begin building the primary function output, mergeIntersectNodes, by enumerating all edges of the input node
    //
    mergeIntersectNodes.clear();

    // loop through each edge connected to the input node
    const SVLocusEdgeManager edgeMap(inputNode.getEdgeManager());
    for (const SVLocusEdgesType::value_type& inputEdge : edgeMap.getMap())
    {
#ifdef DEBUG_SVL
        log_os << logtag << " processing edge: " << inputAddy << "->" << inputLocusIndex << ":" << inputEdge.first << "\n";
        checkState();
#endif

        //
        // for each edge from the input node, get all intersecting edges
        //
        // 'intersecting edge' means that the nodes connected by the two edges each overlap
        //
        std::vector<EdgeInfoType> inputIntersectEdges;
        getIntersectingEdgeNodes(inputLocusIndex, inputEdge.first, remoteIntersectNodeToLocalNodeMap, remoteIntersectNodes, inputIntersectEdges);

        unsigned intersectCount(inputIntersectEdges.size());
        if (! isInputLocusMoved)
        {
            /// TODO: doc this adjustment, does this normalize the edge count to always include self-intersect?
            intersectCount++;
        }

        // isRegionCheck initiates a more detailed evidence signal threshold check process
        //
        // - The default process checks the total evidence summed over the entire
        // Node intersect set. This neglects to account for the possibility that that evidence
        // density could be low, and yet a high evidence sum could be achieved by transitive over
        // lap of many nodes.
        //
        // - The regioncheck pathway sums up evidence at each genomic region. It more accurately
        // reflects peak evidence but is somewhat slower to compute.
        //
        // Example:
        //
        // Assume each node below has an evidence count of 1.
        //
        // |---node1-----|
        //           |-----node2-----|
        //                        |-----node3---|
        //
        // Default evidence count:
        // 33333333333333333333333333333333333333
        //
        // isRegionCheck evidence count:
        // 11111111112222211111111222211111111111
        //
        //

        // peak RegionCheck count will always equal default count when 2 or fewer nodes exist,
        // so there's no reason to turn it on until we have more nodes
        const bool isRegionCheck(intersectCount>2);

        if (isRegionCheck)
        {
            _mergeRegions.clear();
        }

        // enumerate counts as part of the (non-RegionCheck) process to determine if the intersection set
        // contains sufficient evidence to initiate a merge
        unsigned mergedLocalEdgeCount(0);
        unsigned mergedRemoteEdgeCount(0);

        ///
        /// enumerate node evidence using either the default or RegionCheck process:
        ///
        auto addEdgeEvidenceCount = [&](
                                        const SVLocus& edgeLocus,
                                        const NodeIndexType localNodeIndex,
                                        const NodeIndexType remoteNodeIndex)
        {
            // total edge counts on the remote->local edge:
            const unsigned remoteEdgeCount = edgeLocus.getEdge(remoteNodeIndex,localNodeIndex).getCount();

            // total edge counts on the local->remote edge:
            const unsigned localEdgeCount = edgeLocus.getEdge(localNodeIndex,remoteNodeIndex).getCount();

            if (isRegionCheck)
            {
                const known_pos_range2& localRange(edgeLocus.getNode(localNodeIndex).getInterval().range);
                const known_pos_range2& remoteRange(edgeLocus.getNode(remoteNodeIndex).getInterval().range);

                _mergeRegions.localNodeOutbound.add(localRange,localEdgeCount);
                _mergeRegions.localNodeInbound.add(localRange,remoteEdgeCount);
                _mergeRegions.remoteNodeOutbound.add(remoteRange,remoteEdgeCount);
                _mergeRegions.remoteNodeInbound.add(remoteRange,localEdgeCount);
            }
            else
            {
                mergedLocalEdgeCount += localEdgeCount;
                mergedRemoteEdgeCount += remoteEdgeCount;
            }
        };

        for (const EdgeInfoType& edgeInfo : inputIntersectEdges)
        {
            addEdgeEvidenceCount(getLocus(edgeInfo.first.first),edgeInfo.first.second,edgeInfo.second);
        }

        // if the input hasn't been moved into the primary locus graph yet, then we need to include the inputLocus
        // in order to get an accurate edge intersection count:
        if (! isInputLocusMoved)
        {
            addEdgeEvidenceCount(getLocus(inputAddy.first),inputNodeIndex,inputEdge.first);
        }

        if (isRegionCheck)
        {
            mergedLocalEdgeCount=(std::min(_mergeRegions.localNodeOutbound.maxVal(),_mergeRegions.remoteNodeInbound.maxVal()));
            mergedRemoteEdgeCount=(std::min(_mergeRegions.localNodeInbound.maxVal(),_mergeRegions.remoteNodeOutbound.maxVal()));
        }

#ifdef DEBUG_SVL
        log_os << logtag << " isRegionCheck: " << isRegionCheck << "\n";
        log_os << logtag << " final merge counts"
               << " local: " << mergedLocalEdgeCount
               << " remote: " << mergedRemoteEdgeCount
               << "\n";
        checkState();
#endif

        if ((mergedLocalEdgeCount < getMinMergeEdgeCount()) &&
            (mergedRemoteEdgeCount < getMinMergeEdgeCount())) continue;

        //
        // Add type1 mergeable nodes:
        //
        for (const EdgeInfoType& edgeInfo : inputIntersectEdges)
        {
            mergeIntersectNodes.insert(edgeInfo.first);
        }

        /// for each type1 node, add any new intersections to the signal node set:
        ///
        /// this is not very efficient for now -- each type1 edge added in potentially
        /// expands the current node to intersect new signal nodes
        /// -- this loop looks for those new signal nodes
        ///

        {
            // this is used to search for the (rare) case where the intersection set
            // locals overlap with the intersection set remotes
            std::set<NodeAddressType> inputIntersectRemotes;
            for (const EdgeInfoType& edgeInfo : inputIntersectEdges)
            {
                inputIntersectRemotes.insert(std::make_pair(edgeInfo.first.first,edgeInfo.second));
            }

            bool isIntersectRemotes(false);

            // check both the original node and intersected nodes for intersection to
            // any of the group's remotes, and for new type2 signal intersect:
            findSignalNodes(inputLocusIndex, inputAddy, signalIntersectNodes, inputIntersectRemotes, isIntersectRemotes);
            for (const EdgeInfoType& edgeInfo : inputIntersectEdges)
            {
                findSignalNodes(inputLocusIndex, edgeInfo.first, signalIntersectNodes, inputIntersectRemotes, isIntersectRemotes);
            }

            if (isIntersectRemotes)
            {
                for (const NodeAddressType& intersectAddy : inputIntersectRemotes)
                {
#ifdef DEBUG_SVL
                    log_os << logtag << " adding ownRemote: " << intersectAddy << "\n";
#endif
                    mergeIntersectNodes.insert(intersectAddy);

                    // check to see if this adds even more signal nodes!
                    findSignalNodes(inputLocusIndex, intersectAddy, signalIntersectNodes, inputIntersectRemotes, isIntersectRemotes);
                }
            }
        }
        //
        // Add type2 mergeable nodes:
        //
        for (const NodeAddressType& signalAddy : signalIntersectNodes)
        {
            mergeIntersectNodes.insert(signalAddy);
        }
    }

#ifdef DEBUG_SVL
    log_os << logtag << " END. IntersectNodeSize: " << mergeIntersectNodes.size() << " Nodes:\n";
    for (const NodeAddressType addy : mergeIntersectNodes)
    {
        log_os << logtag << "\tInode: " << addy << "\n";
    }
#endif
}
Exemple #3
0
static bool
buildGeodesicSphereData( const float radius, const unsigned int subdivisions, osg::Geometry* geom )
{
    unsigned int subdivide( subdivisions );
    if( subdivisions > 5 )
    {
        // Would create index array too large for use with DrawElementsUShort.
        // For now, clamp. In the future, just use DrawElementsUInt.
        osg::notify( osg::WARN ) << "makeGeodesicSphere: Clamping subdivisions to 5." << std::endl;
        subdivide = 5;
    }

    GLfloat vertData[] = {
        0.000000, 0.850651, 0.525731,
        0.000000, 0.850651, -0.525731,
        0.000000, -0.850651, -0.525731,
        0.000000, -0.850651, 0.525731,
        0.525731, 0.000000, 0.850651,
        0.525731, 0.000000, -0.850651,
        -0.525731, 0.000000, -0.850651,
        -0.525731, 0.000000, 0.850651,
        0.850651, 0.525731, 0.000000,
        0.850651, -0.525731, 0.000000,
        -0.850651, -0.525731, 0.000000,
        -0.850651, 0.525731, 0.000000 };

    int faces = 20;
    int _numVerts = 12;
    int _numIndices = faces * 3;

    // Data is initially in "golden mean" coordinate system.
    // Rotate around y so that 2 verts exist at (0,0,+/-1).
    {
        //osg::Vec3 v0( 0.525731, 0.000000, 0.850651 );
        //osg::Vec3 v1( 0, 0, 1 );
        //const double angle( acos( v0 * v1 ) );
        const double sinAngle( 0.525731 );
        const double cosAngle( 0.850651 );

        int idx;
        for( idx=0; idx<_numVerts*3; idx+=3 )
        {
            double x( vertData[ idx ] );
            double z( vertData[ idx+2 ] );
            vertData[ idx ] = x * cosAngle + z * -sinAngle;
            vertData[ idx+2 ] = x * sinAngle + z * cosAngle;
        }
    }


    int vertsSize = _numVerts * 3;
    GLfloat* _vertices = new GLfloat[ vertsSize ];
    memcpy( _vertices, vertData, sizeof( vertData ) );

    GLushort* _indices = new GLushort[ _numIndices ];
    GLushort* indexPtr = _indices;
    *indexPtr++ = 0;
    *indexPtr++ = 7;
    *indexPtr++ = 4;
    *indexPtr++ = 0;
    *indexPtr++ = 4;
    *indexPtr++ = 8;
    *indexPtr++ = 0;
    *indexPtr++ = 8;
    *indexPtr++ = 1;
    *indexPtr++ = 0;
    *indexPtr++ = 1;
    *indexPtr++ = 11;
    *indexPtr++ = 0;
    *indexPtr++ = 11;
    *indexPtr++ = 7;
    *indexPtr++ = 2;
    *indexPtr++ = 6;
    *indexPtr++ = 5;
    *indexPtr++ = 2;
    *indexPtr++ = 5;
    *indexPtr++ = 9;
    *indexPtr++ = 2;
    *indexPtr++ = 9;
    *indexPtr++ = 3;
    *indexPtr++ = 2;
    *indexPtr++ = 3;
    *indexPtr++ = 10;
    *indexPtr++ = 2;
    *indexPtr++ = 10;
    *indexPtr++ = 6;
    *indexPtr++ = 7;
    *indexPtr++ = 3;
    *indexPtr++ = 4;
    *indexPtr++ = 4;
    *indexPtr++ = 3;
    *indexPtr++ = 9;
    *indexPtr++ = 4;
    *indexPtr++ = 9;
    *indexPtr++ = 8;
    *indexPtr++ = 8;
    *indexPtr++ = 9;
    *indexPtr++ = 5;
    *indexPtr++ = 8;
    *indexPtr++ = 5;
    *indexPtr++ = 1;
    *indexPtr++ = 1;
    *indexPtr++ = 5;
    *indexPtr++ = 6;
    *indexPtr++ = 1;
    *indexPtr++ = 6;
    *indexPtr++ = 11;
    *indexPtr++ = 11;
    *indexPtr++ = 6;
    *indexPtr++ = 10;
    *indexPtr++ = 11;
    *indexPtr++ = 10;
    *indexPtr++ = 7;
    *indexPtr++ = 7;
    *indexPtr++ = 10;
    *indexPtr++ = 3;

    GLuint _idxStart = 0;
    GLuint _idxEnd = 11;


    // Subdivide as requested
    int idx;
    for (idx = subdivide; idx; idx--)
    {
        // Make a map of edges
        typedef std::map< unsigned int, GLushort> EdgeMapType;
        EdgeMapType edgeMap;
        indexPtr = _indices;
        int f;
        for (f=faces; f; f--)
        {
            unsigned int key = makeKey(indexPtr[0], indexPtr[1]);
            if (edgeMap.find( key ) == edgeMap.end())
                edgeMap[key] = ++_idxEnd;

            key = makeKey(indexPtr[1], indexPtr[2]);
            if (edgeMap.find( key ) == edgeMap.end())
                edgeMap[key] = ++_idxEnd;
            
            key = makeKey(indexPtr[2], indexPtr[0]);
            if (edgeMap.find( key ) == edgeMap.end())
                edgeMap[key] = ++_idxEnd;

            indexPtr += 3;
        }

        GLfloat* oldVerts = _vertices;
        GLushort* oldIndices = _indices;

        _numVerts += (int)(faces * 1.5f);
        int newFaces = faces * 4;
        _numIndices = newFaces * 3;

        // Create new indices
        _indices = new GLushort[ _numIndices ];
        GLushort* oldIdxPtr = oldIndices;
        indexPtr = _indices;
        for (f=faces; f; f--)
        {
            GLushort vertA = *oldIdxPtr++;
            GLushort vertB = *oldIdxPtr++;
            GLushort vertC = *oldIdxPtr++;
            GLushort edgeAB = edgeMap[ makeKey(vertA,vertB) ];
            GLushort edgeBC = edgeMap[ makeKey(vertB,vertC) ];
            GLushort edgeCA = edgeMap[ makeKey(vertC,vertA) ];

            *indexPtr++ = vertA;
            *indexPtr++ = edgeAB;
            *indexPtr++ = edgeCA;
            *indexPtr++ = edgeAB;
            *indexPtr++ = vertB;
            *indexPtr++ = edgeBC;
            *indexPtr++ = edgeAB;
            *indexPtr++ = edgeBC;
            *indexPtr++ = edgeCA;
            *indexPtr++ = edgeCA;
            *indexPtr++ = edgeBC;
            *indexPtr++ = vertC;
        }

        // Copy old vertices into new vertices
        _vertices = new GLfloat[ _numVerts * 3 ];
        memcpy( _vertices, oldVerts, vertsSize * sizeof( GLfloat ) );

        // Create new vertices at midpoint of each edge
        EdgeMapType::const_iterator it = edgeMap.begin();
        while (it != edgeMap.end())
        {
            GLushort idxA, idxB;
            idxA = ((*it).first) >> 16;
            idxB = ((*it).first) & 0xffff;

            GLfloat* dest = &(_vertices[ ((*it).second * 3) ]);
            GLfloat* srcA = &(_vertices[idxA*3]);
            GLfloat* srcB = &(_vertices[idxB*3]);
            average3fv( dest, srcA, srcB );

            it++;
        }


        faces = newFaces;
        vertsSize = _numVerts * 3;
        delete[] oldVerts;
        delete[] oldIndices;
    }


    //
    // Create normal array by making vertices unit length
    GLfloat* _normals = new GLfloat[ _numVerts * 3 ];
    GLfloat* vertPtr = _vertices;
    GLfloat* normPtr = _normals;
    for (idx = _numVerts; idx; idx--)
    {
        osg::Vec3 v( vertPtr[0], vertPtr[1], vertPtr[2] );
        float lengthInv = (float)( 1. / v.length() );
        *normPtr++ = *vertPtr++ * lengthInv;
        *normPtr++ = *vertPtr++ * lengthInv;
        *normPtr++ = *vertPtr++ * lengthInv;
    }

    //
    // Scale vertices out to the specified radius
    vertPtr = _vertices;
    normPtr = _normals;
    for (idx = _numVerts*3; idx; idx--)
        *vertPtr++ = *normPtr++ * radius;

    //
    // Texture coordinates are identical to normals for cube mapping
    GLfloat* _texCoords = new GLfloat[ _numVerts * 3 ];
    memcpy( _texCoords, _normals, _numVerts * 3 * sizeof( GLfloat) );


    // Convert to OSG
    {
        osg::Vec3Array* osgV = new osg::Vec3Array;
        osg::Vec3Array* osgN = new osg::Vec3Array;
        osg::Vec3Array* osgTC = new osg::Vec3Array;
        osgV->resize( _numVerts );
        osgN->resize( _numVerts );
        osgTC->resize( _numVerts );

        geom->setVertexArray( osgV );
        geom->setNormalArray( osgN );
        geom->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
        geom->setTexCoordArray( 0, osgTC );

        osg::Vec4Array* osgC = new osg::Vec4Array;
        osgC->push_back( osg::Vec4( 1., 1., 1., 1. ) );
        geom->setColorArray( osgC );
        geom->setColorBinding( osg::Geometry::BIND_OVERALL );

        vertPtr = _vertices;
        normPtr = _normals;
        GLfloat* tcPtr = _texCoords;
        int idx;
        for( idx=0; idx<_numVerts; idx++ )
        {
            (*osgV)[ idx ].x() = *vertPtr++;
            (*osgV)[ idx ].y() = *vertPtr++;
            (*osgV)[ idx ].z() = *vertPtr++;
            (*osgN)[ idx ].x() = *normPtr++;
            (*osgN)[ idx ].y() = *normPtr++;
            (*osgN)[ idx ].z() = *normPtr++;
            (*osgTC)[ idx ].x() = *tcPtr++;
            (*osgTC)[ idx ].y() = *tcPtr++;
            (*osgTC)[ idx ].z() = *tcPtr++;
        }

        osg::UShortArray* osgIdx = new osg::UShortArray;
        osgIdx->resize( _numIndices );
        indexPtr = _indices;
        for( idx=0; idx<_numIndices; idx++ )
        {
            (*osgIdx)[ idx ] = *indexPtr++;
        }

        geom->addPrimitiveSet( new osg::DrawElementsUShort( GL_TRIANGLES, _numIndices, _indices ) );
    }


    delete[] _indices;
    delete[] _vertices;
    delete[] _normals;
    delete[] _texCoords;

    osg::notify( osg::INFO ) << "makeGeodesicSphere: numVertices: " << _numVerts << std::endl;
    return( true );
}