2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.renderer;
23 import java.util.Arrays;
24 import java.util.Iterator;
25 import java.util.List;
27 import jalview.datamodel.ColumnSelection;
28 import jalview.datamodel.ContactListI;
29 import jalview.datamodel.HiddenColumns;
30 import jalview.renderer.ContactGeometry.contactInterval;
33 * encapsulate logic for mapping between positions in a ContactList and their
34 * rendered representation in a given number of pixels.
39 public class ContactGeometry
42 final ContactListI contacts;
45 * how many pixels per contact (1..many)
47 final int pixels_step;
50 * how many contacts per pixel (many > 0)
52 final double contacts_per_pixel;
55 * number of contacts being mapped
57 final int contact_height;
60 * number of pixels to map contact_height to
62 final int graphHeight;
65 * number of contacts for each pixel_step - to last whole contact
67 final double contacts_step;
72 * Bean used to map from a range of contacts to a range of pixels
76 * Number of pixels to map given range of contacts
78 public ContactGeometry(final ContactListI contacts, int graphHeight)
80 this.contacts = contacts;
81 this.graphHeight = graphHeight;
82 contact_height = contacts.getContactHeight();
83 // fractional number of contacts covering each pixel
84 contacts_per_pixel = (graphHeight <= 1) ? contact_height
85 : ((double) contact_height) / ((double) graphHeight);
87 if (contacts_per_pixel >= 1)
89 // many contacts rendered per pixel
94 // pixel height for each contact
95 pixels_step = (int) Math
96 .ceil(((double) graphHeight) / (double) contact_height);
98 contacts_step = pixels_step * contacts_per_pixel;
99 lastStep = (int) Math.min((double) graphHeight,
100 ((double) graphHeight) / ((double) pixels_step));
103 public class contactInterval
105 public contactInterval(int cStart, int cEnd, int pStart, int pEnd)
107 this.cStart = cStart;
109 this.pStart = pStart;
113 // range on contact list
114 public final int cStart;
116 public final int cEnd;
119 public final int pStart;
121 public final int pEnd;
124 public boolean equals(Object obj)
126 if (obj == null || !(obj instanceof contactInterval))
130 contactInterval them = (contactInterval) obj;
131 return cStart == them.cStart && cEnd == them.cEnd && pEnd == them.pEnd
132 && pStart == them.pStart;
136 public String toString()
138 return "Contacts [" + cStart + "," + cEnd + "] : Pixels [" + pStart
145 * @param columnSelection
148 * - when true, only test intersection of visible columns given
150 * @return true if the range on the matrix specified by ci intersects with
151 * selected columns in the ContactListI's reference frame.
154 boolean intersects(contactInterval ci, ColumnSelection columnSelection,
155 HiddenColumns hiddenColumns, boolean visibleOnly)
157 boolean rowsel = false;
158 final int[] mappedRange = contacts.getMappedPositionsFor(ci.cStart,
160 if (mappedRange == null)
164 for (int p = 0; p < mappedRange.length && !rowsel; p += 2)
166 boolean containsHidden = false;
167 if (visibleOnly && hiddenColumns != null
168 && hiddenColumns.hasHiddenColumns())
170 // TODO: turn into function on hiddenColumns and create test !!
171 Iterator<int[]> viscont = hiddenColumns.getVisContigsIterator(
172 -1 + mappedRange[p], -1 + mappedRange[p + 1], false);
173 containsHidden = !viscont.hasNext();
176 for (int[] interval = viscont.next(); viscont
177 .hasNext(); rowsel |= columnSelection
178 .intersects(interval[p], interval[p + 1]))
184 rowsel = columnSelection.intersects(-1 + mappedRange[p],
185 -1 + mappedRange[p + 1]);
193 * Return mapped cell intersecting pStart \
195 * FIXME: REDUNDANT METHOD - COULD DELETE FIXME: OR RE-IMPLEMENT AS EFFICIENT
201 * @return nearest full cell containing pStart - does not set
202 * contactInterval.pEnd or cEnd to equivalent position on pEnd !
204 public contactInterval mapFor(int pStart, int pEnd)
214 if (pEnd >= graphHeight)
216 pEnd = graphHeight - 1;
218 if (pStart >= graphHeight)
220 pStart = graphHeight - pixels_step;
222 int step = Math.floorDiv(pStart, pixels_step);
223 return findStep(step);
229 * [0..) n steps covering height and contactHeight
230 * @return contactInterval for step, or null if out of bounds
232 contactInterval findStep(int step)
234 if (step < 0 || step > lastStep)
238 return new contactInterval((int) Math.floor(contacts_step * step),
239 -1 + (int) Math.min(contact_height,
240 Math.floor(contacts_step * (step + 1))),
242 Math.min(graphHeight, (step + 1) * pixels_step) - 1);
246 * return the cell containing given pixel
249 * @return range for pCEntre
251 public contactInterval mapFor(int pCentre)
253 if (pCentre >= graphHeight + pixels_step)
257 int step = Math.floorDiv(pCentre, pixels_step);
258 return findStep(step);
261 public List<contactInterval> allSteps()
263 contactInterval[] array = new contactInterval[lastStep + 1];
264 int csum = 0, psum = 0;
265 for (int i = 0; i <= lastStep; i++)
267 array[i] = findStep(i);
268 csum += 1 + array[i].cEnd - array[i].cStart;
269 psum += 1 + array[i].pEnd - array[i].pStart;
271 if (csum != contact_height || psum != graphHeight)
273 System.err.println("csum = " + csum + " not " + contact_height + "\n"
274 + "psum = " + psum + " not " + graphHeight);
277 return Arrays.asList(array);
280 public Iterator<contactInterval> iterateOverContactIntervals(
283 // NOT YET IMPLEMENTED
285 // int cstart = 0, cend;
288 // eht = y2 - graphHeight; ht >= eht; ht -= pixels_step)
290 // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
291 // cend = (int) Math.min(contact_height,
292 // Math.ceil(cstart + contacts_per_pixel * pixels_step));
294 // return new Iterator<contactIntervals>() {
297 // public boolean hasNext()
299 // // TODO Auto-generated method stub
304 // public contactIntervals next()
306 // // TODO Auto-generated method stub