+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview 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.
+ *
+ * Jalview 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 Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.renderer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactListI;
+import jalview.datamodel.ContactRange;
+import jalview.datamodel.Mapping;
+import jalview.datamodel.SeqDistanceContactMatrix;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+import jalview.util.MapList;
+import jalview.util.StringUtils;
+import jalview.ws.datamodel.MappableContactMatrixI;
+
+public class ContactGeometryTest
+{
+ @Test(groups="Functional")
+ public void testCoverageofRange()
+ {
+ // a really dumb test to make sure we really cover the requested pixel and
+ // contactList range for any dimension of each
+ for (int range = 12; range < 2000; range += 35)
+ {
+ StringBuilder sb = new StringBuilder();
+ while (sb.length() < range)
+ {
+ sb.append("c");
+ }
+ SequenceI sq = new Sequence("a", sb.toString());
+ MappableContactMatrixI cm = new SeqDistanceContactMatrix(range);
+ AlignmentAnnotation cm_aan = sq.addContactList(cm);
+ ContactListI cl = sq.getContactListFor(cm_aan, 10);
+ assertNotNull(cl);
+ for (int ht = range / 2; ht < range * 3; ht++)
+ {
+ ContactGeometry clgeom = new ContactGeometry(cl, ht);
+ assertNotNull(clgeom.allSteps());
+ }
+ }
+ }
+ @Test(groups = "Functional")
+ public void testContactGeometry()
+ {
+ SequenceI sq = new Sequence("a", "SSSQ");
+ MappableContactMatrixI cm = new SeqDistanceContactMatrix(4);
+ AlignmentAnnotation cm_aan = sq.addContactList(cm);
+ checkConsistencyFor(sq,cm_aan);
+ // Also check all is good when there's a sequence mapping involved
+ MappableContactMatrixI newcm=cm.liftOver(sq,
+ new Mapping(sq, new MapList(new int[]
+ { 1, 4 }, new int[] { 1, 4 }, 1, 1)));
+ AlignmentAnnotation mapped_cm = sq.addContactList(newcm);
+ checkConsistencyFor(sq,mapped_cm);
+ }
+ // Do some asserts for a sequence and a contact matrix
+ private void checkConsistencyFor(SequenceI sq, AlignmentAnnotation cm_aan)
+ {
+ int col=1;
+ ContactListI cl = sq.getContactListFor(cm_aan, col);
+ assertNotNull(cl);
+ assertEquals(cl.getContactHeight(),4);
+
+ // Map contacts 0 to 3 to a tiny range and check
+ ContactGeometry testee = new ContactGeometry(cl,2);
+ assertEquals(testee.contacts_per_pixel,2d);
+ ContactGeometry.contactInterval lastInterval = testee.mapFor(1);
+ assertEquals(lastInterval.cStart,2);
+ assertEquals(lastInterval.cEnd,3);
+ assertEquals(lastInterval.pStart,1);
+ assertEquals(lastInterval.pEnd,1);
+ ContactGeometry.contactInterval another = testee.mapFor(1,2);
+ assertEquals(lastInterval,another);
+ // Also check for a big pixel range
+ testee = new ContactGeometry(cl, 395);
+ lastInterval = testee.mapFor(390, 395); // 395 is one over limit.
+ assertNotNull(lastInterval);
+ assertEquals(lastInterval.cEnd,3);
+ assertEquals(lastInterval.pEnd,394);
+ // Map contacts 0 to 3 to Pixels 0-9, 10-19, 20-29, 30-39
+ testee = new ContactGeometry(cl, 40);
+
+ // verify mapping from pixel to contacts
+
+ // renderer thinks base 0 for pixel coordinates
+ // contact coordinates are base 1
+ for (int p = 0; p < 40; p++)
+ {
+ int expectC=(p / 10);
+ int expectP=(expectC)*10;
+ ContactGeometry.contactInterval ci_at = testee.mapFor(p),
+ ci_from = testee.mapFor(p, p);
+ assertNotNull(ci_at);
+ // mapFor and map should locate the same pixel window
+ assertEquals(ci_at.cStart, expectC,"Different cStart at position "+p);
+ assertEquals(ci_at.cEnd, expectC,"Different cEnd at position "+p);
+ assertEquals(ci_at.pStart,expectP, "Different pStart at position "+p);
+ assertEquals(ci_at.pEnd,expectP+9, "Different pEnd at position "+p);
+
+ assertEquals(ci_from,ci_at, "Different contactIntervals at position "+p);
+ // also test getRangeFor
+ ContactRange cr = cl.getRangeFor(ci_at.cStart, ci_at.cEnd);
+ assertEquals(cr.getFrom_column(),cr.getTo_column());
+ assertEquals((double) cr.getMean(),(double)Math.abs(col-cr.getFrom_column()), "Didn't resolve expected value at position "+p);
+ }
+
+ ContactGeometry.contactInterval ci_at0 = testee.mapFor(0);
+ ContactGeometry.contactInterval ci_at9 = testee.mapFor(9);
+ assertNotNull(ci_at9);
+
+ assertEquals(ci_at0,ci_at9);
+
+ // Adjacent cell
+ ContactGeometry.contactInterval ci_at10 = testee.mapFor(10);
+ assertNotNull(ci_at10);
+ ContactGeometry.contactInterval ci_at11 = testee.mapFor(11);
+ assertNotNull(ci_at11);
+
+ assertEquals(ci_at11,ci_at10,"Off-by-one in ContactGeometry mapping.");
+
+ assertNotEquals(ci_at0,ci_at10,"Expected adjacent cells to be not equal.");
+
+ // verify adjacent window is mapped
+ assertEquals(ci_at11.cStart,ci_at9.cStart+1);
+
+ assertEquals(ci_at9.cEnd+1,ci_at11.cStart);
+ assertEquals(ci_at9.cEnd+1,ci_at11.cEnd);
+
+ // verify interval/intersection
+ // column selection is base 0
+ ColumnSelection cs = new ColumnSelection();
+ cs.addElement(2);
+
+ boolean mask = false;
+ do
+ {
+ assertFalse(testee.intersects(ci_at0, cs, null, mask));
+ assertFalse(testee.intersects(ci_at11, cs, null, mask));
+ assertTrue(testee.intersects(testee.mapFor(21), cs, null, mask));
+ assertFalse(testee.intersects(testee.mapFor(31), cs, null, mask));
+ cs.addElement(3);
+ assertTrue(testee.intersects(testee.mapFor(31), cs, null, mask));
+ cs.removeElement(2);
+ assertFalse(testee.intersects(testee.mapFor(21), cs, null, mask));
+ mask = !mask;
+ } while (!mask);
+
+ }
+}