JAL-2349 allow PAE or other contact matrices to hold a coordinate mapping allowing...
[jalview.git] / src / jalview / renderer / ContactGeometry.java
index 0e5107a..2eb325c 100644 (file)
@@ -2,21 +2,39 @@ package jalview.renderer;
 
 import java.util.Iterator;
 
+import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.ContactListI;
+import jalview.datamodel.HiddenColumns;
+import jalview.renderer.ContactGeometry.contactInterval;
 
+/**
+ * encapsulate logic for mapping between positions in a ContactList and their
+ * rendered representation in a given number of pixels.
+ * 
+ * @author jprocter
+ *
+ */
 public class ContactGeometry
 {
+  
+  final ContactListI contacts;
+  
   final int pixels_step;
 
   final double contacts_per_pixel;
 
   final int contact_height;
 
-  public ContactGeometry(ContactListI contacts, int graphHeight)
+  final int graphHeight;
+
+  public ContactGeometry(final ContactListI contacts, int graphHeight)
   {
+    this.contacts=contacts;
+    this.graphHeight = graphHeight;
     contact_height = contacts.getContactHeight();
     // fractional number of contacts covering each pixel
-    contacts_per_pixel = ((double) contact_height) / ((double) graphHeight);
+    contacts_per_pixel = (graphHeight < 1) ? contact_height
+            : ((double) contact_height) / ((double) graphHeight);
 
     if (contacts_per_pixel >= 1)
     {
@@ -50,6 +68,47 @@ public class ContactGeometry
     public final int pStart;
 
     public final int 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.
+   */
+  
+  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)
+    {
+      return false;
+    }
+    boolean containsHidden=false;
+    if (visibleOnly && hiddenColumns!=null && hiddenColumns.hasHiddenColumns())
+    {
+      // TODO: turn into function on hiddenColumns and create test !!
+      Iterator<int[]> viscont = hiddenColumns
+              .getVisContigsIterator(mappedRange[0], mappedRange[1], false);
+      containsHidden = !viscont.hasNext();
+      if (!containsHidden)
+      {
+        for (int[] interval=viscont.next();viscont.hasNext();
+        rowsel |= columnSelection.intersects(interval[0],interval[1]))
+          ;
+      }
+    }
+    else
+    {
+      // if containsHidden is true mappedRange is not visible
+      if (containsHidden)
+      {
+        rowsel = columnSelection.intersects(mappedRange[0], mappedRange[1]);
+      }
+    }
+    return rowsel;
+
   }
 
   /**
@@ -70,6 +129,25 @@ public class ContactGeometry
     return ci;
   }
 
+  /**
+   * return the cell containing given pixel
+   * 
+   * @param pCentre
+   * @return range for pCEntre
+   */
+  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;
+  }
+
   public Iterator<contactInterval> iterateOverContactIntervals(
           int graphHeight)
   {