overlaps = seq.getFeatures().findFeatures(
visiblePositions.getBegin(), visiblePositions.getEnd(), type);
if (overlaps.size() > 1 && fc.isSimpleColour())
{
filterFeaturesForDisplay(overlaps);
}
for (SequenceFeature sf : overlaps)
{
Color featureColour = getColor(sf, fc);
if (featureColour == null)
{
/*
* feature excluded by filters, or colour threshold
*/
continue;
}
/*
* if feature starts/ends outside the visible range,
* restrict to visible positions (or if a contact feature,
* to a single position)
*/
int visibleStart = sf.getBegin();
if (visibleStart < visiblePositions.getBegin())
{
visibleStart = sf.isContactFeature() ? sf.getEnd()
: visiblePositions.getBegin();
}
int visibleEnd = sf.getEnd();
if (visibleEnd > visiblePositions.getEnd())
{
visibleEnd = sf.isContactFeature() ? sf.getBegin()
: visiblePositions.getEnd();
}
int featureStartCol = seq.findIndex(visibleStart);
int featureEndCol = sf.begin == sf.end ? featureStartCol
: seq.findIndex(visibleEnd);
// Color featureColour = getColour(sequenceFeature);
boolean isContactFeature = sf.isContactFeature();
if (isContactFeature)
{
boolean drawn = renderFeature(g, seq, featureStartCol - 1,
featureStartCol - 1, featureColour, start, end, y1,
colourOnly);
drawn |= renderFeature(g, seq, featureEndCol - 1,
featureEndCol - 1, featureColour, start, end, y1,
colourOnly);
if (drawn)
{
drawnColour = featureColour;
}
}
else
{
/*
* showing feature score by height of colour
* is not implemented as a selectable option
*
if (av.isShowSequenceFeaturesHeight()
&& !Float.isNaN(sequenceFeature.score))
{
boolean drawn = renderScoreFeature(g, seq,
seq.findIndex(sequenceFeature.begin) - 1,
seq.findIndex(sequenceFeature.end) - 1, featureColour,
start, end, y1, normaliseScore(sequenceFeature),
colourOnly);
if (drawn)
{
drawnColour = featureColour;
}
}
else
{
*/
boolean drawn = renderFeature(g, seq, featureStartCol - 1,
featureEndCol - 1, featureColour, start, end, y1,
colourOnly);
if (drawn)
{
drawnColour = featureColour;
}
/*}*/
}
}
}
/*
* draw 'complement' features above ours if configured to do so
*/
if (av.isShowComplementFeatures() && av.isShowComplementFeaturesOnTop())
{
drawnColour = drawComplementFeatures(g, seq, start, end, y1,
colourOnly, visiblePositions, drawnColour);
}
if (transparency != 1.0f && g != null)
{
/*
* reset transparency
*/
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(NO_TRANSPARENCY);
}
return drawnColour;
}
/**
* Find any features on the CDS/protein complement of the sequence region and
* draw them, with visibility and colouring as configured in the complementary
* viewport
*
* @param g
* @param seq
* @param start
* @param end
* @param y1
* @param colourOnly
* @param visiblePositions
* @param drawnColour
* @return
*/
Color drawComplementFeatures(final Graphics g, final SequenceI seq,
int start, int end, int y1, boolean colourOnly,
ContiguousI visiblePositions, Color drawnColour)
{
AlignViewportI comp = av.getCodingComplement();
FeatureRenderer fr2 = Desktop.getAlignFrameFor(comp)
.getFeatureRenderer();
final int visibleStart = visiblePositions.getBegin();
final int visibleEnd = visiblePositions.getEnd();
for (int pos = visibleStart; pos <= visibleEnd; pos++)
{
int column = seq.findIndex(pos);
MappedFeatures mf = fr2.findComplementFeaturesAtResidue(seq, pos);
if (mf != null)
{
for (SequenceFeature sf : mf.features)
{
FeatureColourI fc = fr2.getFeatureStyle(sf.getType());
Color featureColour = fr2.getColor(sf, fc);
renderFeature(g, seq, column - 1, column - 1, featureColour,
start, end, y1, colourOnly);
drawnColour = featureColour;
}
}
}
return drawnColour;
}
/**
* Called when alignment in associated view has new/modified features to
* discover and display.
*
*/
@Override
public void featuresAdded()
{
findAllFeatures();
}
/**
* Returns the sequence feature colour rendered at the given column position,
* or null if none found. The feature of highest render order (i.e. on top) is
* found, subject to both feature type and feature group being visible, and
* its colour returned. This method is suitable when no feature transparency
* applied (only the topmost visible feature colour is rendered).
*
* Note this method does not check for a gap in the column so would return the
* colour for features enclosing a gapped column. Check for gap before calling
* if different behaviour is wanted.
*
* @param seq
* @param column
* (1..)
* @return
*/
Color findFeatureColour(SequenceI seq, int column)
{
/*
* check for new feature added while processing
*/
updateFeatures();
/*
* show complement features on top (if configured to show them)
*/
if (av.isShowComplementFeatures() && av.isShowComplementFeaturesOnTop())
{
Color col = findComplementFeatureColour(seq, column);
if (col != null)
{
return col;
}
}
/*
* inspect features in reverse renderOrder (the last in the array is
* displayed on top) until we find one that is rendered at the position
*/
for (int renderIndex = renderOrder.length
- 1; renderIndex >= 0; renderIndex--)
{
String type = renderOrder[renderIndex];
if (!showFeatureOfType(type))
{
continue;
}
List overlaps = seq.findFeatures(column, column,
type);
for (SequenceFeature sequenceFeature : overlaps)
{
if (!featureGroupNotShown(sequenceFeature))
{
Color col = getColour(sequenceFeature);
if (col != null)
{
return col;
}
}
}
}
/*
* show complement features underneath (if configured to show them)
*/
Color col = null;
if (av.isShowComplementFeatures()
&& !av.isShowComplementFeaturesOnTop())
{
col = findComplementFeatureColour(seq, column);
}
return col;
}
Color findComplementFeatureColour(SequenceI seq, int column)
{
AlignViewportI complement = av.getCodingComplement();
AlignFrame af = Desktop.getAlignFrameFor(complement);
FeatureRendererModel fr2 = af.getFeatureRenderer();
MappedFeatures mf = fr2.findComplementFeaturesAtResidue(seq,
seq.findPosition(column - 1));
if (mf == null)
{
return null;
}
ReverseListIterator it = new ReverseListIterator<>(
mf.features);
while (it.hasNext())
{
SequenceFeature sf = it.next();
if (!fr2.featureGroupNotShown(sf))
{
Color col = fr2.getColour(sf);
if (col != null)
{
return col;
}
}
}
return null;
}
}