//Copyright 2017 Ryan Wick
//This file is part of Bandage.
//Bandage 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.
//Bandage 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 for more details.
//You should have received a copy of the GNU General Public License
//along with Bandage. If not, see .
#include "graphlocation.h"
#include "debruijnnode.h"
#include "assemblygraph.h"
#include "../program/globals.h"
GraphLocation::GraphLocation() :
m_node(0), m_position(0)
{
}
GraphLocation::GraphLocation(DeBruijnNode * node, int position) :
m_node(node), m_position(position)
{
}
GraphLocation GraphLocation::startOfNode(DeBruijnNode * node)
{
GraphLocation location(node, 1);
if (location.isValid())
return location;
else
return GraphLocation::null();
}
GraphLocation GraphLocation::endOfNode(DeBruijnNode * node)
{
if (node == 0)
return GraphLocation::null();
int pos = node->getLength();
GraphLocation location(node, pos);
if (location.isValid())
return location;
else
return GraphLocation::null();
}
GraphLocation GraphLocation::null()
{
return GraphLocation(0, 0);
}
bool GraphLocation::isValid() const
{
if (isNull())
return false;
if (m_position < 1)
return false;
return m_position <= m_node->getLength();
}
bool GraphLocation::isNull() const
{
return (m_node == 0 || m_position == 0);
}
GraphLocation GraphLocation::reverseComplementLocation() const
{
int newPos = m_node->getLength() - m_position + 1;
GraphLocation newLocation(m_node->getReverseComplement(), newPos);
//For Velvet graphs, the reverse complement location is shifted by the k-mer
//size and may not even be on the same node!
if (g_assemblyGraph->m_graphFileType == LAST_GRAPH)
newLocation.moveLocation(-g_assemblyGraph->m_kmer + 1);
if (newLocation.isValid())
return newLocation;
else
return GraphLocation::null();
}
void GraphLocation::moveLocation(int change)
{
if (change > 0)
moveForward(change);
else if (change < 0)
moveBackward(-change);
}
void GraphLocation::moveForward(int change)
{
//See if there are enough bases left in this node to move by the
//required amount. If so, we're done!
int basesLeftInNode = m_node->getLength() - m_position;
if (change <= basesLeftInNode)
{
m_position += change;
return;
}
//If there aren't enough bases left, then we recursively try with the
//next nodes.
std::vector downstreamNodes = m_node->getDownstreamNodes();
for (size_t i = 0; i < downstreamNodes.size(); ++i)
{
DeBruijnNode * node = downstreamNodes[i];
GraphLocation nextNodeLocation = GraphLocation::startOfNode(node);
nextNodeLocation.moveForward(change - basesLeftInNode - 1);
if (nextNodeLocation.isValid())
{
m_node = nextNodeLocation.getNode();
m_position = nextNodeLocation.getPosition();
return;
}
}
//If the code got here, then we failed to move and we make this a null
//position.
m_node = 0;
m_position = 0;
return;
}
void GraphLocation::moveBackward(int change)
{
//See if there are enough bases left in this node to move by the
//required amount. If so, we're done!
int basesLeftInNode = m_position - 1;
if (change <= basesLeftInNode)
{
m_position -= change;
return;
}
//If there aren't enough bases left, then we recursively try with the
//next nodes.
std::vector upstreamNodes = m_node->getUpstreamNodes();
for (size_t i = 0; i < upstreamNodes.size(); ++i)
{
DeBruijnNode * node = upstreamNodes[i];
GraphLocation nextNodeLocation = GraphLocation::endOfNode(node);
nextNodeLocation.moveBackward(change - basesLeftInNode - 1);
if (nextNodeLocation.isValid())
{
m_node = nextNodeLocation.getNode();
m_position = nextNodeLocation.getPosition();
return;
}
}
//If the code got here, then we failed to move and we make this a null
//position.
m_node = 0;
m_position = 0;
return;
}
char GraphLocation::getBase() const
{
if (!isValid())
return '\0';
else
return m_node->getBaseAt(m_position - 1);
}
bool GraphLocation::isAtStartOfNode() const
{
return (isValid() && m_position == 1);
}
bool GraphLocation::isAtEndOfNode() const
{
return (isValid() && m_position == m_node->getLength());
}
bool GraphLocation::operator==(GraphLocation const &other) const
{
return (m_node == other.m_node && m_position == other.m_position);
}