Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.gui

File RotatableCanvas.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

100
222
30
1
887
548
87
0.39
7.4
30
2.9

Classes

Class Line # Actions
RotatableCanvas 57 222 87 352
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.gui;
22   
23    import jalview.api.RotatableCanvasI;
24    import jalview.datamodel.SequenceGroup;
25    import jalview.datamodel.SequenceI;
26    import jalview.datamodel.SequencePoint;
27    import jalview.math.RotatableMatrix;
28    import jalview.util.MessageManager;
29    import jalview.viewmodel.AlignmentViewport;
30   
31    import java.awt.Color;
32    import java.awt.Dimension;
33    import java.awt.Font;
34    import java.awt.Graphics;
35    import java.awt.Graphics2D;
36    import java.awt.Image;
37    import java.awt.RenderingHints;
38    import java.awt.event.InputEvent;
39    import java.awt.event.KeyEvent;
40    import java.awt.event.KeyListener;
41    import java.awt.event.MouseEvent;
42    import java.awt.event.MouseListener;
43    import java.awt.event.MouseMotionListener;
44    import java.awt.event.MouseWheelEvent;
45    import java.awt.event.MouseWheelListener;
46    import java.util.Vector;
47   
48    import javax.swing.JPanel;
49    import javax.swing.ToolTipManager;
50   
51    /**
52    * DOCUMENT ME!
53    *
54    * @author $author$
55    * @version $Revision$
56    */
 
57    public class RotatableCanvas extends JPanel implements MouseListener,
58    MouseMotionListener, KeyListener, RotatableCanvasI
59    {
60    RotatableMatrix idmat = new RotatableMatrix(3, 3);
61   
62    RotatableMatrix objmat = new RotatableMatrix(3, 3);
63   
64    RotatableMatrix rotmat = new RotatableMatrix(3, 3);
65   
66    // RubberbandRectangle rubberband;
67    boolean drawAxes = true;
68   
69    int omx = 0;
70   
71    int mx = 0;
72   
73    int omy = 0;
74   
75    int my = 0;
76   
77    Image img;
78   
79    Graphics ig;
80   
81    Dimension prefsize;
82   
83    float[] centre = new float[3];
84   
85    float[] width = new float[3];
86   
87    float[] max = new float[3];
88   
89    float[] min = new float[3];
90   
91    float maxwidth;
92   
93    float scale;
94   
95    int npoint;
96   
97    Vector points;
98   
99    float[][] orig;
100   
101    float[][] axes;
102   
103    int startx;
104   
105    int starty;
106   
107    int lastx;
108   
109    int lasty;
110   
111    int rectx1;
112   
113    int recty1;
114   
115    int rectx2;
116   
117    int recty2;
118   
119    float scalefactor = 1;
120   
121    AlignmentViewport av;
122   
123    AlignmentPanel ap;
124   
125    boolean showLabels = false;
126   
127    Color bgColour = Color.black;
128   
129    boolean applyToAllViews = false;
130   
 
131  0 toggle public RotatableCanvas(AlignmentPanel ap)
132    {
133  0 this.av = ap.av;
134  0 this.ap = ap;
135   
136  0 addMouseWheelListener(new MouseWheelListener()
137    {
 
138  0 toggle @Override
139    public void mouseWheelMoved(MouseWheelEvent e)
140    {
141  0 double wheelRotation = e.getPreciseWheelRotation();
142  0 if (wheelRotation > 0)
143    {
144    /*
145    * zoom in
146    */
147  0 scale = (float) (scale * 1.1);
148  0 repaint();
149    }
150  0 else if (wheelRotation < 0)
151    {
152    /*
153    * zoom out
154    */
155  0 scale = (float) (scale * 0.9);
156  0 repaint();
157    }
158    }
159    });
160   
161    }
162   
 
163  0 toggle public void showLabels(boolean b)
164    {
165  0 showLabels = b;
166  0 repaint();
167    }
168   
169    boolean first = true;
170   
 
171  0 toggle @Override
172    public void setPoints(Vector points, int npoint)
173    {
174  0 this.points = points;
175  0 this.npoint = npoint;
176  0 if (first)
177    {
178  0 ToolTipManager.sharedInstance().registerComponent(this);
179  0 ToolTipManager.sharedInstance().setInitialDelay(0);
180  0 ToolTipManager.sharedInstance().setDismissDelay(10000);
181    }
182  0 prefsize = getPreferredSize();
183  0 orig = new float[npoint][3];
184   
185  0 for (int i = 0; i < npoint; i++)
186    {
187  0 SequencePoint sp = (SequencePoint) points.elementAt(i);
188   
189  0 for (int j = 0; j < 3; j++)
190    {
191  0 orig[i][j] = sp.coord[j];
192    }
193    }
194   
195    // Initialize the matrices to identity
196  0 for (int i = 0; i < 3; i++)
197    {
198  0 for (int j = 0; j < 3; j++)
199    {
200  0 if (i != j)
201    {
202  0 idmat.addElement(i, j, 0);
203  0 objmat.addElement(i, j, 0);
204  0 rotmat.addElement(i, j, 0);
205    }
206    else
207    {
208  0 idmat.addElement(i, j, 0);
209  0 objmat.addElement(i, j, 0);
210  0 rotmat.addElement(i, j, 0);
211    }
212    }
213    }
214   
215  0 axes = new float[3][3];
216  0 initAxes();
217   
218  0 findCentre();
219  0 findWidth();
220   
221  0 scale = findScale();
222  0 if (first)
223    {
224   
225  0 addMouseListener(this);
226   
227  0 addMouseMotionListener(this);
228    }
229  0 first = false;
230    }
231   
 
232  0 toggle public void initAxes()
233    {
234  0 for (int i = 0; i < 3; i++)
235    {
236  0 for (int j = 0; j < 3; j++)
237    {
238  0 if (i != j)
239    {
240  0 axes[i][j] = 0;
241    }
242    else
243    {
244  0 axes[i][j] = 1;
245    }
246    }
247    }
248    }
249   
250    /**
251    * DOCUMENT ME!
252    */
 
253  0 toggle public void findWidth()
254    {
255  0 max = new float[3];
256  0 min = new float[3];
257   
258  0 max[0] = (float) -1e30;
259  0 max[1] = (float) -1e30;
260  0 max[2] = (float) -1e30;
261   
262  0 min[0] = (float) 1e30;
263  0 min[1] = (float) 1e30;
264  0 min[2] = (float) 1e30;
265   
266  0 for (int i = 0; i < 3; i++)
267    {
268  0 for (int j = 0; j < npoint; j++)
269    {
270  0 SequencePoint sp = (SequencePoint) points.elementAt(j);
271   
272  0 if (sp.coord[i] >= max[i])
273    {
274  0 max[i] = sp.coord[i];
275    }
276   
277  0 if (sp.coord[i] <= min[i])
278    {
279  0 min[i] = sp.coord[i];
280    }
281    }
282    }
283   
284    // System.out.println("xmax " + max[0] + " min " + min[0]);
285    // System.out.println("ymax " + max[1] + " min " + min[1]);
286    // System.out.println("zmax " + max[2] + " min " + min[2]);
287  0 width[0] = Math.abs(max[0] - min[0]);
288  0 width[1] = Math.abs(max[1] - min[1]);
289  0 width[2] = Math.abs(max[2] - min[2]);
290   
291  0 maxwidth = width[0];
292   
293  0 if (width[1] > width[0])
294    {
295  0 maxwidth = width[1];
296    }
297   
298  0 if (width[2] > width[1])
299    {
300  0 maxwidth = width[2];
301    }
302   
303    // System.out.println("Maxwidth = " + maxwidth);
304    }
305   
306    /**
307    * DOCUMENT ME!
308    *
309    * @return DOCUMENT ME!
310    */
 
311  0 toggle public float findScale()
312    {
313  0 int dim;
314  0 int width;
315  0 int height;
316   
317  0 if (getWidth() != 0)
318    {
319  0 width = getWidth();
320  0 height = getHeight();
321    }
322    else
323    {
324  0 width = prefsize.width;
325  0 height = prefsize.height;
326    }
327   
328  0 if (width < height)
329    {
330  0 dim = width;
331    }
332    else
333    {
334  0 dim = height;
335    }
336   
337  0 return (dim * scalefactor) / (2 * maxwidth);
338    }
339   
340    /**
341    * DOCUMENT ME!
342    */
 
343  0 toggle public void findCentre()
344    {
345    // Find centre coordinate
346  0 findWidth();
347   
348  0 centre[0] = (max[0] + min[0]) / 2;
349  0 centre[1] = (max[1] + min[1]) / 2;
350  0 centre[2] = (max[2] + min[2]) / 2;
351   
352    // System.out.println("Centre x " + centre[0]);
353    // System.out.println("Centre y " + centre[1]);
354    // System.out.println("Centre z " + centre[2]);
355    }
356   
357    /**
358    * DOCUMENT ME!
359    *
360    * @return DOCUMENT ME!
361    */
 
362  0 toggle @Override
363    public Dimension getPreferredSize()
364    {
365  0 if (prefsize != null)
366    {
367  0 return prefsize;
368    }
369    else
370    {
371  0 return new Dimension(400, 400);
372    }
373    }
374   
375    /**
376    * DOCUMENT ME!
377    *
378    * @return DOCUMENT ME!
379    */
 
380  0 toggle @Override
381    public Dimension getMinimumSize()
382    {
383  0 return getPreferredSize();
384    }
385   
386    /**
387    * DOCUMENT ME!
388    *
389    * @param g
390    * DOCUMENT ME!
391    */
 
392  0 toggle @Override
393    public void paintComponent(Graphics g1)
394    {
395   
396  0 Graphics2D g = (Graphics2D) g1;
397   
398  0 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
399    RenderingHints.VALUE_ANTIALIAS_ON);
400  0 if (points == null)
401    {
402  0 g.setFont(new Font("Verdana", Font.PLAIN, 18));
403  0 g.drawString(
404    MessageManager.getString("label.calculating_pca") + "....",
405    20, getHeight() / 2);
406    }
407    else
408    {
409    // Only create the image at the beginning -
410  0 if ((img == null) || (prefsize.width != getWidth())
411    || (prefsize.height != getHeight()))
412    {
413  0 prefsize.width = getWidth();
414  0 prefsize.height = getHeight();
415   
416  0 scale = findScale();
417   
418    // System.out.println("New scale = " + scale);
419  0 img = createImage(getWidth(), getHeight());
420  0 ig = img.getGraphics();
421    }
422   
423  0 drawBackground(ig, bgColour);
424  0 drawScene(ig);
425   
426  0 if (drawAxes == true)
427    {
428  0 drawAxes(ig);
429    }
430   
431  0 g.drawImage(img, 0, 0, this);
432    }
433    }
434   
435    /**
436    * DOCUMENT ME!
437    *
438    * @param g
439    * DOCUMENT ME!
440    */
 
441  0 toggle public void drawAxes(Graphics g)
442    {
443   
444  0 g.setColor(Color.yellow);
445   
446  0 for (int i = 0; i < 3; i++)
447    {
448  0 g.drawLine(getWidth() / 2, getHeight() / 2,
449    (int) ((axes[i][0] * scale * max[0]) + (getWidth() / 2)),
450    (int) ((axes[i][1] * scale * max[1]) + (getHeight() / 2)));
451    }
452    }
453   
454    /**
455    * DOCUMENT ME!
456    *
457    * @param g
458    * DOCUMENT ME!
459    * @param col
460    * DOCUMENT ME!
461    */
 
462  0 toggle public void drawBackground(Graphics g, Color col)
463    {
464  0 g.setColor(col);
465  0 g.fillRect(0, 0, prefsize.width, prefsize.height);
466    }
467   
468    /**
469    * DOCUMENT ME!
470    *
471    * @param g
472    * DOCUMENT ME!
473    */
 
474  0 toggle public void drawScene(Graphics g1)
475    {
476   
477  0 Graphics2D g = (Graphics2D) g1;
478   
479  0 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
480    RenderingHints.VALUE_ANTIALIAS_ON);
481   
482  0 int halfwidth = getWidth() / 2;
483  0 int halfheight = getHeight() / 2;
484   
485  0 for (int i = 0; i < npoint; i++)
486    {
487  0 SequencePoint sp = (SequencePoint) points.elementAt(i);
488  0 int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth;
489  0 int y = (int) ((sp.coord[1] - centre[1]) * scale)
490    + halfheight;
491  0 float z = sp.coord[1] - centre[2];
492   
493  0 if (av.getSequenceColour(sp.sequence) == Color.black)
494    {
495  0 g.setColor(Color.white);
496    }
497    else
498    {
499  0 g.setColor(av.getSequenceColour(sp.sequence));
500    }
501   
502  0 if (av.getSelectionGroup() != null)
503    {
504  0 if (av.getSelectionGroup().getSequences(null)
505    .contains(((SequencePoint) points.elementAt(i)).sequence))
506    {
507  0 g.setColor(Color.gray);
508    }
509    }
510   
511  0 if (z < 0)
512    {
513  0 g.setColor(g.getColor().darker());
514    }
515   
516  0 g.fillRect(x - 3, y - 3, 6, 6);
517  0 if (showLabels)
518    {
519  0 g.setColor(Color.red);
520  0 g.drawString(
521    ((SequencePoint) points.elementAt(i)).sequence.getName(),
522    x - 3, y - 4);
523    }
524    }
525   
526    // //Now the rectangle
527    // if (rectx2 != -1 && recty2 != -1) {
528    // g.setColor(Color.white);
529    //
530    // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
531    // }
532    }
533   
534    /**
535    * DOCUMENT ME!
536    *
537    * @return DOCUMENT ME!
538    */
 
539  0 toggle public Dimension minimumsize()
540    {
541  0 return prefsize;
542    }
543   
544    /**
545    * DOCUMENT ME!
546    *
547    * @return DOCUMENT ME!
548    */
 
549  0 toggle public Dimension preferredsize()
550    {
551  0 return prefsize;
552    }
553   
554    /**
555    * DOCUMENT ME!
556    *
557    * @param evt
558    * DOCUMENT ME!
559    */
 
560  0 toggle @Override
561    public void keyTyped(KeyEvent evt)
562    {
563    }
564   
565    /**
566    * DOCUMENT ME!
567    *
568    * @param evt
569    * DOCUMENT ME!
570    */
 
571  0 toggle @Override
572    public void keyReleased(KeyEvent evt)
573    {
574    }
575   
576    /**
577    * DOCUMENT ME!
578    *
579    * @param evt
580    * DOCUMENT ME!
581    */
 
582  0 toggle @Override
583    public void keyPressed(KeyEvent evt)
584    {
585  0 if (evt.getKeyCode() == KeyEvent.VK_UP)
586    {
587  0 scalefactor = (float) (scalefactor * 1.1);
588  0 scale = findScale();
589    }
590  0 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
591    {
592  0 scalefactor = (float) (scalefactor * 0.9);
593  0 scale = findScale();
594    }
595  0 else if (evt.getKeyChar() == 's')
596    {
597  0 System.err.println("DEBUG: Rectangle selection"); // log.debug
598   
599  0 if ((rectx2 != -1) && (recty2 != -1))
600    {
601  0 rectSelect(rectx1, recty1, rectx2, recty2);
602    }
603    }
604   
605  0 repaint();
606    }
607   
608    /**
609    * DOCUMENT ME!
610    *
611    * @param evt
612    * DOCUMENT ME!
613    */
 
614  0 toggle @Override
615    public void mouseClicked(MouseEvent evt)
616    {
617    }
618   
619    /**
620    * DOCUMENT ME!
621    *
622    * @param evt
623    * DOCUMENT ME!
624    */
 
625  0 toggle @Override
626    public void mouseEntered(MouseEvent evt)
627    {
628    }
629   
630    /**
631    * DOCUMENT ME!
632    *
633    * @param evt
634    * DOCUMENT ME!
635    */
 
636  0 toggle @Override
637    public void mouseExited(MouseEvent evt)
638    {
639    }
640   
641    /**
642    * DOCUMENT ME!
643    *
644    * @param evt
645    * DOCUMENT ME!
646    */
 
647  0 toggle @Override
648    public void mouseReleased(MouseEvent evt)
649    {
650    }
651   
652    /**
653    * DOCUMENT ME!
654    *
655    * @param evt
656    * DOCUMENT ME!
657    */
 
658  0 toggle @Override
659    public void mousePressed(MouseEvent evt)
660    {
661  0 int x = evt.getX();
662  0 int y = evt.getY();
663   
664  0 mx = x;
665  0 my = y;
666   
667  0 omx = mx;
668  0 omy = my;
669   
670  0 startx = x;
671  0 starty = y;
672   
673  0 rectx1 = x;
674  0 recty1 = y;
675   
676  0 rectx2 = -1;
677  0 recty2 = -1;
678   
679  0 SequenceI found = findPoint(x, y);
680   
681  0 if (found != null)
682    {
683  0 AlignmentPanel[] aps = getAssociatedPanels();
684   
685  0 for (int a = 0; a < aps.length; a++)
686    {
687  0 if (aps[a].av.getSelectionGroup() != null)
688    {
689  0 aps[a].av.getSelectionGroup().addOrRemove(found, true);
690    }
691    else
692    {
693  0 aps[a].av.setSelectionGroup(new SequenceGroup());
694  0 aps[a].av.getSelectionGroup().addOrRemove(found, true);
695  0 aps[a].av.getSelectionGroup()
696    .setEndRes(aps[a].av.getAlignment().getWidth() - 1);
697    }
698    }
699  0 PaintRefresher.Refresh(this, av.getSequenceSetId());
700    // canonical selection is sent to other listeners
701  0 av.sendSelection();
702    }
703   
704  0 repaint();
705    }
706   
707    // private void fireSequenceSelectionEvent(Selection sel) {
708    // controller.handleSequenceSelectionEvent(new
709    // SequenceSelectionEvent(this,sel));
710    // }
 
711  0 toggle @Override
712    public void mouseMoved(MouseEvent evt)
713    {
714  0 SequenceI found = findPoint(evt.getX(), evt.getY());
715   
716  0 if (found != null)
717    {
718  0 this.setToolTipText(found.getName());
719    }
720    else
721    {
722  0 this.setToolTipText(null);
723    }
724    }
725   
726    /**
727    * DOCUMENT ME!
728    *
729    * @param evt
730    * DOCUMENT ME!
731    */
 
732  0 toggle @Override
733    public void mouseDragged(MouseEvent evt)
734    {
735  0 mx = evt.getX();
736  0 my = evt.getY();
737   
738    // Check if this is a rectangle drawing drag
739  0 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
740    {
741    // rectx2 = evt.getX();
742    // recty2 = evt.getY();
743    }
744    else
745    {
746  0 rotmat.setIdentity();
747   
748  0 rotmat.rotate(my - omy, 'x');
749  0 rotmat.rotate(mx - omx, 'y');
750   
751  0 for (int i = 0; i < npoint; i++)
752    {
753  0 SequencePoint sp = (SequencePoint) points.elementAt(i);
754  0 sp.coord[0] -= centre[0];
755  0 sp.coord[1] -= centre[1];
756  0 sp.coord[2] -= centre[2];
757   
758    // Now apply the rotation matrix
759  0 sp.coord = rotmat.vectorMultiply(sp.coord);
760   
761    // Now translate back again
762  0 sp.coord[0] += centre[0];
763  0 sp.coord[1] += centre[1];
764  0 sp.coord[2] += centre[2];
765    }
766   
767  0 for (int i = 0; i < 3; i++)
768    {
769  0 axes[i] = rotmat.vectorMultiply(axes[i]);
770    }
771   
772  0 omx = mx;
773  0 omy = my;
774   
775  0 paint(this.getGraphics());
776    }
777    }
778   
779    /**
780    * DOCUMENT ME!
781    *
782    * @param x1
783    * DOCUMENT ME!
784    * @param y1
785    * DOCUMENT ME!
786    * @param x2
787    * DOCUMENT ME!
788    * @param y2
789    * DOCUMENT ME!
790    */
 
791  0 toggle public void rectSelect(int x1, int y1, int x2, int y2)
792    {
793  0 for (int i = 0; i < npoint; i++)
794    {
795  0 SequencePoint sp = (SequencePoint) points.elementAt(i);
796  0 int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale)
797    + (getWidth() / 2.0));
798  0 int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale)
799    + (getHeight() / 2.0));
800   
801  0 if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
802    {
803  0 if (av != null)
804    {
805  0 if (!av.getSelectionGroup().getSequences(null)
806    .contains(sp.sequence))
807    {
808  0 av.getSelectionGroup().addSequence(sp.sequence, true);
809    }
810    }
811    }
812    }
813   
814    // if (changedSel) {
815    // fireSequenceSelectionEvent(av.getSelection());
816    // }
817    }
818   
819    /**
820    * DOCUMENT ME!
821    *
822    * @param x
823    * DOCUMENT ME!
824    * @param y
825    * DOCUMENT ME!
826    *
827    * @return DOCUMENT ME!
828    */
 
829  0 toggle public SequenceI findPoint(int x, int y)
830    {
831  0 int halfwidth = getWidth() / 2;
832  0 int halfheight = getHeight() / 2;
833   
834  0 int found = -1;
835   
836  0 for (int i = 0; i < npoint; i++)
837    {
838  0 SequencePoint sp = (SequencePoint) points.elementAt(i);
839  0 int px = (int) ((sp.coord[0] - centre[0]) * scale)
840    + halfwidth;
841  0 int py = (int) ((sp.coord[1] - centre[1]) * scale)
842    + halfheight;
843   
844  0 if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
845    {
846  0 found = i;
847    }
848    }
849   
850  0 if (found != -1)
851    {
852  0 return ((SequencePoint) points.elementAt(found)).sequence;
853    }
854    else
855    {
856  0 return null;
857    }
858    }
859   
 
860  0 toggle AlignmentPanel[] getAssociatedPanels()
861    {
862  0 if (applyToAllViews)
863    {
864  0 return PaintRefresher.getAssociatedPanels(av.getSequenceSetId());
865    }
866    else
867    {
868  0 return new AlignmentPanel[] { ap };
869    }
870    }
871   
872    /**
873    *
874    * @return x,y,z positions of point s (index into points) under current
875    * transform.
876    */
 
877  0 toggle public double[] getPointPosition(int s)
878    {
879  0 double pts[] = new double[3];
880  0 float[] p = ((SequencePoint) points.elementAt(s)).coord;
881  0 pts[0] = p[0];
882  0 pts[1] = p[1];
883  0 pts[2] = p[2];
884  0 return pts;
885    }
886   
887    }