X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Frenderer%2FContactGeometry.java;h=a1443c82cec29f357abfe974f60cf85a24821eab;hb=cb31e23d9138e481479623374aed7767bf8934d2;hp=2eb325c46ce8b97838ec1e36857fcb1395eeb937;hpb=9e40070f757fc662aba39ba6314be4937276ead4;p=jalview.git diff --git a/src/jalview/renderer/ContactGeometry.java b/src/jalview/renderer/ContactGeometry.java index 2eb325c..a1443c8 100644 --- a/src/jalview/renderer/ContactGeometry.java +++ b/src/jalview/renderer/ContactGeometry.java @@ -1,6 +1,8 @@ package jalview.renderer; +import java.util.Arrays; import java.util.Iterator; +import java.util.List; import jalview.datamodel.ColumnSelection; import jalview.datamodel.ContactListI; @@ -16,24 +18,48 @@ import jalview.renderer.ContactGeometry.contactInterval; */ public class ContactGeometry { - + final ContactListI contacts; - + + /** + * how many pixels per contact (1..many) + */ final int pixels_step; + /** + * how many contacts per pixel (many > 0) + */ final double contacts_per_pixel; + /** + * number of contacts being mapped + */ final int contact_height; + /** + * number of pixels to map contact_height to + */ final int graphHeight; + /** + * number of contacts for each pixel_step - to last whole contact + */ + final double contacts_step; + + final int lastStep; + + /** + * Bean used to map from a range of contacts to a range of pixels + * @param contacts + * @param graphHeight Number of pixels to map given range of contacts + */ public ContactGeometry(final ContactListI contacts, int graphHeight) { - this.contacts=contacts; + this.contacts = contacts; this.graphHeight = graphHeight; contact_height = contacts.getContactHeight(); // fractional number of contacts covering each pixel - contacts_per_pixel = (graphHeight < 1) ? contact_height + contacts_per_pixel = (graphHeight <= 1) ? contact_height : ((double) contact_height) / ((double) graphHeight); if (contacts_per_pixel >= 1) @@ -47,6 +73,8 @@ public class ContactGeometry pixels_step = (int) Math .ceil(((double) graphHeight) / (double) contact_height); } + contacts_step = pixels_step*contacts_per_pixel; + lastStep = (int) Math.min((double)graphHeight, ((double)graphHeight)/((double)pixels_step)); } public class contactInterval @@ -69,42 +97,67 @@ public class ContactGeometry public final int pEnd; + @Override + public boolean equals(Object obj) + { + if (obj == null || !(obj instanceof contactInterval)) + { + return false; + } + contactInterval them = (contactInterval) obj; + return cStart == them.cStart && cEnd == them.cEnd && pEnd == them.pEnd + && pStart == them.pStart; + } + @Override + public String toString() + { + return "Contacts ["+cStart+","+cEnd+"] : Pixels ["+pStart+","+pEnd+"]"; + } } + /** * * @param columnSelection * @param ci - * @param visibleOnly - when true, only test intersection of visible columns given matrix range - * @return true if the range on the matrix specified by ci intersects with selected columns in the ContactListI's reference frame. + * @param visibleOnly + * - when true, only test intersection of visible columns given + * matrix range + * @return true if the range on the matrix specified by ci intersects with + * selected columns in the ContactListI's reference frame. */ - - boolean intersects(contactInterval ci,ColumnSelection columnSelection, HiddenColumns hiddenColumns, boolean visibleOnly) { + + boolean intersects(contactInterval ci, ColumnSelection columnSelection, + HiddenColumns hiddenColumns, boolean visibleOnly) + { boolean rowsel = false; - final int[] mappedRange = contacts.getMappedPositionsFor(ci.cStart, ci.cEnd); - if (mappedRange==null) + final int[] mappedRange = contacts.getMappedPositionsFor(ci.cStart, + ci.cEnd); + if (mappedRange == null) { return false; } - boolean containsHidden=false; - if (visibleOnly && hiddenColumns!=null && hiddenColumns.hasHiddenColumns()) + for (int p = 0; p < mappedRange.length && !rowsel; p += 2) { - // TODO: turn into function on hiddenColumns and create test !! - Iterator viscont = hiddenColumns - .getVisContigsIterator(mappedRange[0], mappedRange[1], false); - containsHidden = !viscont.hasNext(); - if (!containsHidden) + boolean containsHidden = false; + if (visibleOnly && hiddenColumns != null + && hiddenColumns.hasHiddenColumns()) { - for (int[] interval=viscont.next();viscont.hasNext(); - rowsel |= columnSelection.intersects(interval[0],interval[1])) - ; + // TODO: turn into function on hiddenColumns and create test !! + Iterator viscont = hiddenColumns.getVisContigsIterator( + -1+mappedRange[p], -1+mappedRange[p + 1], false); + containsHidden = !viscont.hasNext(); + if (!containsHidden) + { + for (int[] interval = viscont.next(); viscont + .hasNext(); rowsel |= columnSelection + .intersects(interval[p], interval[p + 1])) + ; + } } - } - else - { - // if containsHidden is true mappedRange is not visible - if (containsHidden) + else { - rowsel = columnSelection.intersects(mappedRange[0], mappedRange[1]); + rowsel = columnSelection.intersects(-1+mappedRange[p], + -1+mappedRange[p + 1]); } } return rowsel; @@ -112,21 +165,56 @@ public class ContactGeometry } /** + * Return mapped cell intersecting pStart \ + * + * FIXME: REDUNDANT METHOD - COULD DELETE FIXME: OR RE-IMPLEMENT AS EFFICIENT + * RANGE QUERY * * @param pStart + * [0..) * @param pEnd - * @return range for + * @return nearest full cell containing pStart - does not set + * contactInterval.pEnd or cEnd to equivalent position on pEnd ! */ public contactInterval mapFor(int pStart, int pEnd) { - int cStart = (int) Math.floor(pStart * contacts_per_pixel); - contactInterval ci = new contactInterval(cStart, - (int) Math.min(contact_height, - Math.ceil( - cStart + (pEnd - pStart) * contacts_per_pixel)), - pStart, pEnd); - - return ci; + if (pStart < 0) + { + pStart = 0; + } + if (pEnd < pStart) + { + pEnd = pStart; + } + if (pEnd >= graphHeight) + { + pEnd = graphHeight - 1; + } + if (pStart >= graphHeight) + { + pStart = graphHeight - pixels_step; + } + int step = Math.floorDiv(pStart, pixels_step); + return findStep(step); + } + + /** + * + * @param step + * [0..) n steps covering height and contactHeight + * @return contactInterval for step, or null if out of bounds + */ + contactInterval findStep(int step) + { + if (step < 0 || step > lastStep) + { + return null; + } + return new contactInterval((int) Math.floor(contacts_step * step), + -1 + (int) Math.min(contact_height, + Math.floor(contacts_step * (step + 1))), + pixels_step * step, + Math.min(graphHeight, (step + 1) * pixels_step) - 1); } /** @@ -137,15 +225,31 @@ public class ContactGeometry */ public contactInterval mapFor(int pCentre) { - int pStart = Math.max(pCentre - pixels_step, 0); - int pEnd = Math.min(pStart + pixels_step, graphHeight); - int cStart = (int) Math.floor(pStart * contacts_per_pixel); - contactInterval ci = new contactInterval(cStart, - (int) Math.min(contact_height, - Math.ceil(cStart + (pixels_step) * contacts_per_pixel)), - pStart, pEnd); - - return ci; + if (pCentre >= graphHeight + pixels_step) + { + return null; + } + int step = Math.floorDiv(pCentre, pixels_step); + return findStep(step); + } + + public List allSteps() + { + contactInterval[] array = new contactInterval[lastStep + 1]; + int csum = 0, psum = 0; + for (int i = 0; i <= lastStep; i++) + { + array[i] = findStep(i); + csum += 1 + array[i].cEnd - array[i].cStart; + psum += 1 + array[i].pEnd - array[i].pStart; + } + if (csum != contact_height || psum != graphHeight) + { + System.err.println("csum = " + csum + " not " + contact_height + "\n" + + "psum = " + psum + " not " + graphHeight); + return null; + } + return Arrays.asList(array); } public Iterator iterateOverContactIntervals(