}
if (reference!=null) {
int sbend = cursor+range[i];
- if (sbend>=rlength) {
+ if (sbend>rlength) {
sq.append(reference.substring(cursor, rlength));
while (sbend-- >= rlength)
{
}
/**
- * inefficient add one operation to cigar string
+ * add an operation to cigar string
* @param op char
* @param range int
*/
* NOTE: Insertion operations simply extend width of cigar result - affecting registration of alignment
* Deletion ops will shorten length of result - and affect registration of alignment
* Match ops will also affect length of result - affecting registration of alignment
- * (ie "10M".insert(4,I,3)->"4M3I3M")
- * (ie "10M".insert(4,D,3)->"4M3D3M")
- * (ie "5I5M".insert(4,I,3)->"8I5M")
- * (ie "5I5M".insert(4,D,3)->"4I3M")
- * if pos is beyond width - I operations are added before the operation
- * (ie "10M".insert(4,M,3)->"13M")
+ * (ie "10M".insert(4,I,3)->"4M3I3M") - (replace?)
+ * (ie "10M".insert(4,D,3)->"4M3D3M") - (shortens alignment)
+ * (ie "5I5M".insert(4,I,3)->"8I5M") - real insertion
+ * (ie "5I5M".insert(4,D,3)->"4I2D3M") - shortens aligment - I's are removed, Ms changed to Ds
+ * (ie "10M".insert(4,M,3)->"13M") - lengthens - Is changed to M, Ds changed to M.
* (ie "5I5M".insert(4,M,3)->"4I8M") - effectively shifts sequence left by 1 residue and extends it by 3
- * @param pos int
+ * ( "10D5M".insert(-1,M,3)->"3M7D5M")
+ * ( "10D5M".insert(0,M,3)->"7D8M")
+ * ( "10D5M".insert(1,M,3)->"10D8M")
+ *
+ * ( "1M10D5M".insert(0,M,3)->"1M10D8M")
+ * ( "1M10D5M".insert(1,M,3)->"
+ *
+ * if pos is beyond width - I operations are added before the operation
+ * @param pos int -1, 0-length of visible region, or greater to append new ops (with insertions in between)
* @param op char
* @param range int
- */
public void addOperationAt(int pos, char op, int range)
{
+ int cursor = -1; // mark the position for the current operation being edited.
+ int o = 0;
+ boolean last_d = false; // previous op was a deletion.
+ if (pos < -1)
+ throw new Error("pos<-1 is not supported.");
+ while (o<length) {
+ if (operation[o] != D)
+ {
+ if ( (cursor + this.range[o]) < pos)
+ {
+ cursor += this.range[o];
+ o++;
+ last_d=false;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else {
+ last_d=true;
+ o++;
+ }
+ }
+ if (o==length) {
+ // must insert more operations before pos
+ if (pos-cursor>0)
+ addInsertion(pos-cursor);
+ // then just add the new operation. Regardless of what it is.
+ addOperation(op, range);
+ } else {
+ int diff = pos - cursor;
+ int e_length = length-o; // new edit operation array length.
+ // diff<0 - can only happen before first insertion or match. - affects op and all following
+ // dif==0 - only when at first position of existing op -
+ // diff>0 - must preserve some existing operations
+ int[] e_range = new int[e_length];
+ System.arraycopy(this.range, o, e_range, 0, e_length);
+ char[] e_op = new char[e_length];
+ System.arraycopy(this.operation, o, e_op, 0, e_length);
+ length = o; // can now use add_operation to extend list.
+ int e_o=0; // current operation being edited.
+ switch (op) {
+ case M:
+ switch (e_op[e_o])
+ {
+ case M:
+ if (last_d && diff <= 0)
+ {
+ // reduce D's, if possible
+ if (range<=this.range[o-1]) {
+ this.range[o - 1] -= range;
+ } else {
+ this.range[o-1]=0;
+ }
+ if (this.range[o-1]==0)
+ o--; // lose this op.
+ }
+ e_range[e_o] += range; // just add more matched residues
+ break;
+ case I:
+ // change from insertion to match
+ if (last_d && diff<=0)
+ {
+ // reduce D's, if possible
+ if (range<=this.range[o-1]) {
+ this.range[o - 1] -= range;
+ } else {
+ this.range[o-1]=0;
+ }
+ if (this.range[o-1]==0)
+ o--; // lose this op.
+ }
+ e_range[e_o]
+ break;
+ default:
+ throw new Inp
+ }
+
+ break;
+ case I:
+ break;
+ case D:
+ }
+ break;
+ default:
+ throw new Error("Implementation Error: Unknown operation in addOperation!");
+ }
+ // finally, add remaining ops.
+ while (e_o<e_length) {
+ addOperation(e_op[e_o], e_range[e_o]);
+ e_o++;
+ }
+ }
}
+**/
+ /**
+ * Mark residues from start to end (inclusive) as deleted from the alignment, and removes any insertions.
+ * @param start int
+ * @param end int
+ */
+ public void deleteRange(int start, int end) {
+ if (length==0) {
+ // nothing to do here
+ return;
+ }
+ if (start<0 || start>end)
+ throw new Error("Implementation Error: deleteRange out of bounds: start must be non-negative and less than end.");
+ // find beginning
+ int cursor = 0; // mark the position for the current operation being edited.
+ int rlength=1+end-start; // number of positions to delete
+ int oldlen=length;
+ int o = 0;
+ boolean editing=false;
+ char[] oldops = operation;
+ int[] oldrange = range;
+ length=0;
+ operation = null;
+ range = null;
+ while (o<oldlen && cursor<=end && rlength>0) {
+ if (oldops[o] == D) {
+ // absorbed into new deleted region.
+ addDeleted(oldrange[o++]);
+ continue;
+ }
+ int remain = oldrange[o]; // number of op characters left to edit
+ if (!editing) {
+ if ( (cursor + remain) <= start)
+ {
+ addOperation(oldops[o],oldrange[o]);
+ cursor+=oldrange[o++];
+ continue; // next operation
+ }
+ editing=true;
+ // add operations before hidden region
+ if (start-cursor>0) {
+ addOperation(oldops[o], start- cursor);
+ remain -= start - cursor;
+ }
+ }
+ // start inserting new ops
+ if (o<oldlen && editing && rlength>0 && remain>0) {
+ switch (oldops[o]) {
+ case M:
+ if (rlength>remain) {
+ addDeleted(remain);
+ } else {
+ addDeleted(rlength);
+ if (remain-rlength>0)
+ this.addOperation(M,remain-rlength); // add remaining back.
+ rlength=0;
+ remain=0;
+ }
+ break;
+ case I:
+ if (remain-rlength>0) {
+ // only remove some gaps
+ addInsertion(remain-rlength);
+ rlength=0;
+ }
+ break;
+ case D:
+ throw new Error("Implementation error."); // do nothing;
+ default:
+ throw new Error("Implementation Error! Unknown operation '"+oldops[o]+"'");
+ }
+ rlength-=remain;
+ remain = oldrange[++o]; // number of op characters left to edit
+ }
+ }
+ // add remaining
+ while (o<oldlen) {
+ addOperation(oldops[o],oldrange[o++]);
+ }
+ //if (cursor<(start+1)) {
+ // ran out of ops - nothing to do here ?
+ // addInsertion(start-cursor);
+ //}
+ }
/**
* sum of ranges in cigar string
* @return int number of residues hidden, matched, or gaps inserted into sequence
* @param start alignment column
* @param end alignment column
* @return boolean true if residues were marked as deleted.
- */
public boolean deleteRange(int start, int end)
{
boolean deleted = false;
}
return deleted;
}
-
+*/
/**
* Return an ENSEMBL style cigar string where D may indicates excluded parts of seq
* @return String of form ([0-9]+[IMD])+