View Javadoc

1   package org.catacomb.graph.gui;
2   
3   import org.catacomb.be.Position;
4   import org.catacomb.datalish.Box;
5   import org.catacomb.report.E;
6   
7   
8   
9   public final class WorldTransform {
10  
11      private double wcx;
12      private double wcy;
13  
14      private int pcx;
15      private int pcy;
16  
17      private int width;
18      private int height;
19  
20      private int hx;
21      private int hy;
22  
23      private double dpdwx;
24      private double dpdwy;
25  
26  
27      private int leftMargin = 0;
28      private int rightMargin = 0;
29      private int topMargin = 0;
30      private int bottomMargin = 0;
31  
32  
33      private boolean xRescalable;
34      private boolean yRescalable;
35  
36  
37      private final static int IBIG = 20000;
38      private final static double SMALL = 1.e-7;
39      private final double DBIG = 1.e9;
40  
41      private boolean recordRange;
42  
43  
44      private double aspectRatio;
45      private boolean constantAspectRatio;
46  
47  
48      // following used for each paint to record limits;
49      private double vxmin;
50      private double vxmax;
51      private double vymin;
52      private double vymax;
53      // private boolean drawnInXRange;
54      // private boolean drawnInYRange;
55  
56  
57  
58      // this is inelegant;
59      private boolean trialPanning = false;
60      private double wcxtp;
61      private double wcytp;
62  
63  
64  
65  
66      // for three D rotations
67  //  private double wcz = 0.;
68      private double w2cx, w2cy, w2cz;
69      private double w3cx, w3cy, w3cz;
70      private double m3xx = 1., m3yy = 1., m3zz = 1.;
71      private double m3xy = 0., m3xz = 0., m3yx = 0., m3yz = 0., m3zx = 0., m3zy = 0.;
72      private double[][] m3B; // temp array container of above
73  
74      // for continuous zoom
75      private double zoomCenX, zoomCenY, dpdwx0, dpdwy0, wcx0, wcy0;
76  
77      int nRangeListener;
78      private RangeListener[] rangeListeners;
79  
80      private RotationListener rotationListener;
81  
82      private Size p_pixelSize;
83  
84  
85      public WorldTransform() {
86          setWidth(100);
87          setHeight(100);
88          setXRescalable(true);
89          setYRescalable(true);
90  
91          setAspectRatioFree();
92  
93          dpdwx = 1.;
94          dpdwy = 1.;
95  
96          wcx = 0.;
97          wcy = 0.;
98  
99          nRangeListener = 0;
100         rangeListeners = new RangeListener[10];
101 
102         p_pixelSize = new Size(0., 0.);
103     }
104 
105 
106     public void setCanvasSize(int w, int h) {
107         setWidth(w);
108         setHeight(h);
109     }
110 
111     public int getWidth() {
112         return width;
113     }
114 
115     public int getHeight() {
116         return height;
117     }
118 
119     public int getLeftMargin() {
120         return leftMargin;
121     }
122 
123     public int getBottomMargin() {
124         return bottomMargin;
125     }
126 
127     public final void setMargins(int l, int r, int b, int t) {
128         leftMargin = l;
129         rightMargin = r;
130         topMargin = t;
131         bottomMargin = b;
132     }
133 
134 
135     public boolean isOnCanvas(double x, double y) {
136         return intIsOnCanvas(powx(x), powy(y));
137     }
138 
139 
140     public boolean intIsOnCanvas(int x, int y) {
141         return (x > -10 && x < width + 10 && y > -10 && y < height + 10);
142     }
143 
144 
145 
146     public void addRangeListener(RangeListener rl) {
147         // just throw the array oob exception if it happens... ***
148         rangeListeners[nRangeListener++] = rl;
149         rl.rangeChanged(RangeListener.BOTH, getXYXYLimits());
150     }
151 
152 
153     public void setRotationListener(RotationListener rl) {
154         rotationListener = rl;
155     }
156 
157 
158 
159     public void fixRanges() {
160         notifyRangeChange(RangeListener.BOTH);
161     }
162 
163     public void rangeChange(int axis) {
164         // notifyRangeChange(axis);
165     }
166 
167 
168     public void notifyRangeChange() {
169         notifyRangeChange(RangeListener.BOTH);
170     }
171 
172 
173     public void notifyRangeChange(int axis) {
174         double[] lims = getXYXYLimits();
175         for (int i = 0; i < nRangeListener; i++) {
176             rangeListeners[i].rangeChanged(axis, lims);
177         }
178     }
179 
180 
181     public void setPixelScalingFromTop(double d) {
182         p_setXRange(0., d * getCanvasWidth());
183         p_setYRange(-1. * d * getCanvasHeight(), 0.);
184     }
185 
186 
187 
188     public void setAspectRatioFree() {
189         constantAspectRatio = false;
190     }
191 
192 
193     public void setFixedAspectRatio(double f) {
194         setAspectRatio(f);
195     }
196 
197 
198     public void setAspectRatio(double f) {
199         aspectRatio = f;
200         constantAspectRatio = true;
201     }
202 
203 
204     public void setXRescalable(boolean b) {
205         xRescalable = b;
206     }
207 
208 
209     public void setYRescalable(boolean b) {
210         yRescalable = b;
211     }
212 
213 
214     void clearRanges() {
215         vxmin = DBIG;
216         vymin = DBIG;
217         vxmax = -1 * DBIG;
218         vymax = -1 * DBIG;
219         // drawnInXRange = false;
220         // drawnInYRange = false;
221     }
222 
223 
224     void startRangeRecording() {
225         clearRanges();
226         recordRange = true;
227     }
228 
229 
230     void stopRangeRecording() {
231         recordRange = false;
232     }
233 
234 
235     public void setWidth(int w) {
236         width = w;
237         hx = (width - leftMargin - rightMargin) / 2;
238         if (hx < 2) {
239             hx = 2;
240         }
241         pcx = leftMargin + hx;
242     }
243 
244 
245 
246     public void setHeight(int h) {
247         height = h;
248         hy = (height - topMargin - bottomMargin) / 2;
249         if (hy < 2) {
250             hy = 2;
251         }
252         pcy = bottomMargin + hy;
253     }
254 
255 
256     public int getCanvasWidth() {
257         return width;
258     }
259 
260 
261     public int getCanvasHeight() {
262         return height;
263     }
264 
265 
266     public double getWorldCanvasWidth() {
267         return width / dpdwx;
268     }
269 
270 
271 
272     public boolean isShowing(double x, double y) {
273         int ix = powx(x);
274         int iy = powy(y);
275         return (ix > 5 && iy > 5 && ix < width - 50 && iy < height - 5); // ADHOC
276     }
277 
278 
279     int[] intDeviceX(double[] wx) {
280         int n = wx.length;
281         int[] idev = new int[n];
282         if (recordRange) {
283             for (int i = 0; i < n; i++) {
284                 idev[i] = qpowx(wx[i]);
285             }
286         } else {
287             for (int i = 0; i < n; i++) {
288                 idev[i] = powx(wx[i]);
289             }
290 
291         }
292         return idev;
293     }
294 
295 
296     int[] intDeviceY(double[] wy) {
297         int n = wy.length;
298         int[] idev = new int[n];
299         if (recordRange) {
300             for (int i = 0; i < n; i++) {
301                 idev[i] = qpowy(wy[i]);
302             }
303         } else {
304             for (int i = 0; i < n; i++) {
305                 idev[i] = powy(wy[i]);
306             }
307 
308         }
309         return idev;
310     }
311 
312 
313 
314     float[] floatDeviceX(double[] wx) {
315         int n = wx.length;
316         float[] fdev = new float[n];
317         if (recordRange) {
318             for (int i = 0; i < n; i++) {
319                 fdev[i] = qpowx(wx[i]);
320             }
321         } else {
322             for (int i = 0; i < n; i++) {
323                 fdev[i] = powx(wx[i]);
324             }
325 
326         }
327         return fdev;
328     }
329 
330 
331     float[] floatDeviceY(double[] wy) {
332         int n = wy.length;
333         float[] fdev = new float[n];
334         if (recordRange) {
335             for (int i = 0; i < n; i++) {
336                 fdev[i] = qpowy(wy[i]);
337             }
338         } else {
339             for (int i = 0; i < n; i++) {
340                 fdev[i] = powy(wy[i]);
341             }
342 
343         }
344         return fdev;
345     }
346 
347 
348     public Size getPixelSize() {
349         p_pixelSize.set(1. / dpdwx, 1. / dpdwy);
350         return p_pixelSize;
351     }
352 
353     public double getPixelArea() {
354         return 1./ dpdwx * 1. / dpdwy;
355     }
356 
357 
358     protected final double wopx(int x) {
359         return wcx + (x - pcx) / dpdwx;
360     }
361 
362 
363     protected final double wopy(int y) {
364         return wcy + (height - y - pcy) / dpdwy;
365     }
366 
367 
368 
369     protected final int powx(double xr) {
370         double f = dpdwx * (xr - wcx);
371         if (f > IBIG) {
372             f = IBIG;
373         }
374         if (f < -IBIG) {
375             f = -IBIG;
376         }
377 
378         int ii = (pcx + (int)f);
379 
380         if (recordRange) {
381             if (xr > vxmax) {
382                 vxmax = xr;
383             }
384             if (xr < vxmin) {
385                 vxmin = xr;
386             }
387         }
388         if (ii > 0 && ii < width) {
389             // drawnInXRange = true;
390         }
391         return ii;
392     }
393 
394 
395     protected final int powy(double yr) {
396         double f = dpdwy * (yr - wcy);
397         if (f > IBIG) {
398             f = IBIG;
399         }
400         if (f < -IBIG) {
401             f = -IBIG;
402         }
403 
404         int ii = (height - (pcy + (int)f));
405 
406         if (recordRange) {
407             if (yr > vymax) {
408                 vymax = yr;
409             }
410             if (yr < vymin) {
411                 vymin = yr;
412             }
413 
414         }
415         if (ii > 0 && ii < height) {
416             // drawnInYRange = true;
417         }
418         return ii;
419     }
420 
421 
422 
423     private final int qpowx(double xr) {
424         return (int)(pcx + dpdwx * (xr - wcx));
425     }
426 
427 
428     private final int qpowy(double yr) {
429         return (int)(height - (pcy + dpdwy * (yr - wcy)));
430     }
431 
432 
433 
434     public final int pubPowx(double xr) {
435         return powx(xr);
436     }
437 
438 
439     public final int pubPowy(double yr) {
440         return powy(yr);
441     }
442 
443 
444     public final Position getWorldPosition(int x, int y) {
445         return new Position(wopx(x), wopy(y));
446     }
447 
448 
449     public final double pubWopx(int x) {
450         return wopx(x);
451     }
452 
453 
454     public final double pubWopy(int y) {
455         return wopy(y);
456     }
457 
458 
459 
460     public final int pubPixDx(double dxr) {
461         return (int)(dpdwx * dxr);
462     }
463 
464 
465     public final int pubPixDy(double dyr) {
466         return (int)(dpdwy * dyr);
467     }
468 
469 
470     public final double dPdX() {
471         return dpdwx;
472     }
473 
474 
475     public final double dPdY() {
476         return dpdwy;
477     }
478 
479 
480 
481     public final double pubDyDpix() {
482         return 1. / dpdwy;
483     }
484 
485 
486     public final double pubDxDpix() {
487         return 1. / dpdwx;
488     }
489 
490 
491 
492     public final double wxLeft() {
493         return wcx - hx / dpdwx;
494     }
495 
496 
497     public final double wxRight() {
498         return wcx + hx / dpdwx;
499     }
500 
501 
502     public final double wyBottom() {
503         return wcy - hy / dpdwy;
504     }
505 
506 
507     public final double wyTop() {
508         return wcy + hy / dpdwy;
509     }
510 
511 
512 
513     private final void enforceAspectRatioY() {
514         if (xRescalable) {
515             dpdwx = 1. / aspectRatio * dpdwy;
516         } else if (yRescalable) {
517             dpdwy = aspectRatio * dpdwx;
518         }
519     }
520 
521 
522     private final void enforceAspectRatioX() {
523         if (yRescalable) {
524             dpdwy = aspectRatio * dpdwx;
525         } else if (xRescalable) {
526             dpdwx = 1. / aspectRatio * dpdwy;
527         }
528     }
529 
530 
531     /*
532      * public void shiftRanges (double twcx, double twcy) { // set wcx, wcy such
533      * that the point that is at xdown, ydown in the; // twcx, twcy coordis is
534      * now at x, y;
535      *
536      * double dx, dy; if (xRescalable) { dx = (ms.px - ms.px0) / dpdwx; wcx =
537      * twcx - dx; } if (yRescalable) { dy = (ms.py - ms.py0) / dpdwy; wcy = twcy +
538      * dy; } if (constantAspectRatio) enforceAspectRatioY(); recordLimits(); }
539      */
540 
541 
542 
543     private void zoomAbout(double f, int xc, int yc) {
544         zoomAbout(f, f, xc, yc);
545     }
546 
547 
548     private void zoomAbout(double fx, double fy, int xc, int yc) {
549         xZoomAbout(fx, xc);
550         yZoomAbout(fy, yc);
551         if (constantAspectRatio) {
552             enforceAspectRatioY();
553         }
554         rangeChange(RangeListener.BOTH);
555     }
556 
557 
558 
559     private void xZoomAbout(double f, int xc) {
560         // NB, here, as everywhere, integer coordinates are measured from;
561         // the TOP left corner, so small y is at the top of the window;
562         double xWorld = wopx(xc);
563 
564         if (xc > leftMargin && xRescalable) {
565             wcx = xWorld + f * (wcx - xWorld);
566             dpdwx /= f;
567             if (dpdwx > 1. / SMALL) {
568                 dpdwx = 1. / SMALL;
569             }
570         }
571     }
572 
573 
574     private void yZoomAbout(double f, int yc) {
575         double yWorld = wopy(yc);
576 
577         if (yc < height - bottomMargin && yRescalable) {
578             wcy = yWorld + f * (wcy - yWorld);
579             dpdwy /= f;
580             if (dpdwy > 1. / SMALL) {
581                 dpdwy = 1. / SMALL;
582             }
583         }
584     }
585 
586 
587     void initializeZoom(int xc, int yc) {
588         zoomCenX = wopx(xc);
589         zoomCenY = wopy(yc);
590         dpdwx0 = dpdwx;
591         dpdwy0 = dpdwy;
592         wcx0 = wcx;
593         wcy0 = wcy;
594     }
595 
596 
597     void dragZoom(double fxin, double fyin, int xc, int yc) {
598         double fx = fxin;
599         double fy = fyin;
600         if (constantAspectRatio) {
601             fx = fy;
602         }
603 
604         if (xc > leftMargin && xRescalable) {
605             wcx = zoomCenX + fx * (wcx0 - zoomCenX);
606             dpdwx = dpdwx0 / fx;
607             if (dpdwx > 1. / SMALL) {
608                 dpdwx = 1. / SMALL;
609             }
610         }
611         if (yc < height - bottomMargin && yRescalable) {
612             wcy = zoomCenY + fy * (wcy0 - zoomCenY);
613             dpdwy = dpdwy0 / fy;
614             if (dpdwy > 1. / SMALL) {
615                 dpdwy = 1. / SMALL;
616             }
617         }
618         if (constantAspectRatio) {
619             enforceAspectRatioY();
620         }
621     }
622 
623 
624     /*
625      *
626      *
627      * if (y > topMargin && x < width - rightMargin) {
628      *
629      *
630      *  } if (y < topMargin) { tickGridx = tickGridx + (f < 1. ? -1 : 1); } if (x >
631      * width - rightMargin) { tickGridy = tickGridy + (f < 1. ? -1 : 1); }
632      *
633      * enforceRangeConstraints(); recordLimits(); }
634      *
635      *
636      *
637      */
638 
639 
640 
641     public void reframe(Box b) {
642         setXRange(b.getXmin(), b.getXmax());
643         setYRange(b.getYmin(), b.getYmax());
644         notifyRangeChange();
645     }
646 
647 
648     public void setXRange(double xl, double xh) {
649         p_setXRange(xl, xh);
650     }
651 
652 
653     public void setYRange(double yl, double yh) {
654         p_setYRange(yl, yh);
655     }
656 
657 
658 
659     private void p_setXRange(double xlin, double xhin) {
660         double xl = xlin;
661         double xh = xhin;
662         if (xh < xl) {
663             double xt = xh;
664             xh = xl;
665             xl = xt;
666         }
667 
668         if (xRescalable) {
669             if (xh <= xl) {
670                 xh += 0.5;
671                 xl -= 0.5;
672             }
673             wcx = 0.5 * (xl + xh);
674             if (xh <= xl + SMALL) {
675                 xh = xl + SMALL;
676             }
677             dpdwx = 2. * hx / (xh - xl);
678         }
679 
680 
681         if (constantAspectRatio) {
682             enforceAspectRatioX();
683         }
684 
685         rangeChange(RangeListener.X);
686     }
687 
688 
689     public void ensureCovers(double xl, double yl, double xh, double yh) {
690         // set tighter constraint last; other first to get center
691         if ((xh - xl) * hy > (yh - yl) * hx) {
692             p_setYRange(yl, yh);
693             p_setXRange(xl, xh);
694 
695         } else {
696             p_setXRange(xl, xh);
697             p_setYRange(yl, yh);
698         }
699     }
700 
701 
702     private void p_setYRange(double ylin, double yhin) {
703         double yl = ylin;
704         double yh = yhin;
705         if (yh < yl) {
706             double yt = yh;
707             yh = yl;
708             yl = yt;
709         }
710 
711         if (yRescalable) {
712             if (yh <= yl) {
713                 yl -= 0.5;
714                 yh += 0.5;
715             }
716             wcy = 0.5 * (yl + yh);
717             if (yh <= yl + SMALL) {
718                 yh = yl + SMALL;
719             }
720             dpdwy = 2. * hy / (yh - yl);
721         }
722 
723         if (constantAspectRatio) {
724             enforceAspectRatioY();
725         }
726 
727         rangeChange(RangeListener.Y);
728     }
729 
730 
731 
732     public final double[] getXYXYLimits() {
733         double[] range = new double[4];
734         range[0] = wxLeft();
735         range[1] = wyBottom();
736         range[2] = wxRight();
737         range[3] = wyTop();
738         return range;
739     }
740 
741 
742     public double[] getXRange() {
743         double[] d = { wxLeft(), wxRight() };
744         return d;
745     }
746 
747 
748     public double[] getYRange() {
749         double[] d = { wyBottom(), wyTop() };
750         return d;
751     }
752 
753 
754     public final void setXYXYLimits(double xl, double yl, double xh, double yh) {
755         if (constantAspectRatio) {
756             // assume axect ratio is 1 for now!!! ---------- TODO;
757             if ((xh - xl) / (width - leftMargin - rightMargin) > (yh - yl)
758                     / (height - topMargin - bottomMargin)) {
759 
760                 p_setYRange(yl, yh);
761                 p_setXRange(xl, xh);
762 
763             } else {
764                 p_setXRange(xl, xh);
765                 p_setYRange(yl, yh);
766             }
767 
768         } else {
769             p_setXRange(xl, xh);
770             p_setYRange(yl, yh);
771         }
772     }
773 
774 
775 
776     void applyRecordedRange() {
777         double dx = 0.1 * (vxmax - vxmin);
778         double dy = 0.1 * (vymax - vymin);
779 
780         double xa = vxmin - dx;
781         double xb = vxmax + dx;
782         double ya = vymin - dy;
783         double yb = vymax + dy;
784 
785         if (vxmin > 1.e8 && vxmax < -1.e8) {
786             setXYXYLimits(0., 0., 1., 1.);
787         } else {
788             setXYXYLimits(xa, ya, xb, yb);
789         }
790     }
791 
792 
793 
794     // default mouse coanvas ignores these - subclasses should
795     // do something more useful
796     void boxSelected(int x0, int y0, int x1, int y1) {
797         p_setXRange(wopx(x0), wopx(x1));
798         p_setYRange(wopy(y0), wopy(y1));
799 
800     }
801 
802 
803 
804 
805 
806     void zoom(double fac, int xc, int yc) {
807         zoomAbout(fac, xc, yc);
808     }
809 
810 
811     void zoom(double xfac, double yfac, int xc, int yc) {
812         zoomAbout(xfac, yfac, xc, yc);
813     }
814 
815 
816     void trialPan(int xfrom, int yfrom, int xto, int yto) {
817         if (!trialPanning) {
818             wcxtp = wcx;
819             wcytp = wcy;
820             trialPanning = true;
821         }
822 
823         // not final - should be smarter here - just shift an image EFF;
824         wcx = wcxtp - (wopx(xto) - wopx(xfrom));
825         wcy = wcytp - (wopy(yto) - wopy(yfrom));
826         rangeChange(RangeListener.BOTH);
827 
828     }
829 
830 
831 
832     void permanentPan(int xfrom, int yfrom, int xto, int yto) {
833         if (!trialPanning) {
834             wcxtp = wcx;
835             wcytp = wcy;
836         }
837 
838         wcx = wcxtp - (wopx(xto) - wopx(xfrom));
839         wcy = wcytp - (wopy(yto) - wopy(yfrom));
840 
841 
842         trialPanning = false;
843         rangeChange(RangeListener.BOTH);
844     }
845 
846 
847     public int[] getIntPosition(double x, double y) {
848         int[] ixy = {powx(x), powy(y)};
849         return ixy;
850     }
851 
852 
853 
854 
855     // 3D transforms and mouse manipulation
856 
857 
858     protected final double xProj(double x, double y, double z) {
859         return w2cx + m3xx * (x - w3cx) + m3xy * (y - w3cy) + m3xz * (z - w3cz);
860     }
861 
862     protected final double yProj(double x, double y, double z) {
863         return w2cy + m3yx * (x - w3cx) + m3yy * (y - w3cy) + m3yz * (z - w3cz);
864     }
865 
866     protected final double zProj(double x, double y, double z) {
867         return w2cz + m3zx * (x - w3cx) + m3zy * (y - w3cy) + m3zz * (z - w3cz);
868     }
869 
870 
871     public double[] project(double x, double y, double z) {
872         double[] v = {xProj(x,y,z), yProj(x,y,z), zProj(x,y,z)};
873         return v;
874     }
875 
876 
877     public double[] deProject(double x, double y, double z) {
878         // deproject the point x, y, w3cz into 3D x,y,z
879         double xu = x - w2cx;
880         double yu = y - w2cy;
881         double zu = z - w2cz;
882 
883         double[] v = new double[3];
884         double det = (m3xx * (m3yy * m3zz - m3zy * m3yz) -
885                       m3xy * (m3yx * m3zz - m3zx * m3yz) +
886                       m3xz * (m3yx * m3zy - m3zx * m3yy));
887 
888 
889 
890         v[0] =  w3cx + ((m3xy * (m3yz * zu     - m3zz * yu) -
891                          m3xz * (m3yy * zu     - m3zy * yu) +
892                          xu    * (m3yy * m3zz  - m3zy * m3yz))) / det;
893 
894 
895         v[1] = w3cy + (-(m3xx * (m3yz * zu     - m3zz *  yu) -
896                          m3xz * (m3yx * zu     - m3zx *  yu) +
897                          xu    * (m3yx * m3zz  - m3zx * m3yz))) / det;
898 
899         v[2] =  w3cz + ((m3xx * (m3yy * zu     - m3zy * yu) -
900                          m3xy * (m3yx * zu     - m3zx * yu) +
901                          xu     * (m3yx * m3zy  - m3zx * m3yy))) / det;
902 
903         double wx = xProj(v[0], v[1], v[2]);
904         double wy = yProj(v[0], v[1], v[2]);
905         double wz = zProj(v[0], v[1], v[2]);
906 
907         if (Math.abs(det - 1.) > 0.001) {
908             E.warning("rotation determinant != 1. " + det);
909         }
910         if (Math.abs(x - wx) + Math.abs(y - wy) + Math.abs(z - wz) > 0.001) {
911             E.info("matrix projection error: ");
912             E.info("original " + x + " " + y + " " + z);
913             E.info("deproj   " + v[0] + " " + v[1] + " " + v[2]);
914             E.info("reproj   " + wx + " " + wy + " " + wz);
915         }
916         return v;
917     }
918 
919 
920     public void initializeRotation(int ixcen, int iycen) {
921         double x = wopx(ixcen);
922         double y = wopy(iycen);
923         initializeRotation(x, y, 0.);
924     }
925 
926     public void initializeRotationLocal(double x, double y, double z) {
927         // x, y, z in the local coordinates (point on the cell)
928 
929         initializeRotation(xProj(x, y, z), yProj(x, y, z), zProj(x, y, z));
930     }
931 
932 
933     public void initializeRotation(double x, double y, double z) {
934         double[][] m3T = {{m3xx, m3xy, m3xz},
935             {m3yx, m3yy, m3yz},
936             {m3zx, m3zy, m3zz}
937         };
938         m3B = m3T;
939         double[] v = deProject(x, y, z);
940 
941         w2cx = x;
942         w2cy = y;
943         w2cz = 0.;
944 
945         w3cx = v[0];
946         w3cy = v[1];
947         w3cz = v[2];
948     }
949 
950 
951     final void applyRotation(double[][] mr) {
952         double[][] m3C = new double[3][3];
953         for (int i = 0; i < 3; i++) {
954             for (int j = 0; j < 3; j++) {
955                 for (int k = 0; k < 3; k++) {
956                     m3C[i][j] += mr[i][k] * m3B[k][j];
957                 }
958             }
959         }
960         m3xx = m3C[0][0];
961         m3xy = m3C[0][1];
962         m3xz = m3C[0][2];
963         m3yx = m3C[1][0];
964         m3yy = m3C[1][1];
965         m3yz = m3C[1][2];
966         m3zx = m3C[2][0];
967         m3zy = m3C[2][1];
968         m3zz = m3C[2][2];
969 
970         if (rotationListener != null) {
971             rotationListener.rotationChanged();
972         }
973     }
974 
975 
976     final void axisRotate(double thax, double thr) {
977         // rotate through angle thr about the line in the x-y plane making
978         // angle thax with the line y = 0;
979 
980         double cf = Math.cos(thax);
981         double sf = Math.sin(thax);
982 
983         double cr = Math.cos(thr);
984         double sr = Math.sin(thr);
985 
986         double[][] mr = { {(cf*cf + sf*cr*sf), (cf*sf - sf*cr*cf), (-sr*sf)},
987             {(sf*cf - cf*cr*sf), (sf*sf + cf*cr*cf), (cf*sr)},
988             {(sr*sf), (-sr*cf), cr}
989         };
990 
991         applyRotation(mr);
992     }
993 
994 
995 
996 
997     public void zRotate(double theta) {
998         double cf = Math.cos(theta);
999         double sf = Math.sin(theta);
1000         double[][] mr = { {cf,  sf, 0.},
1001             {-sf, cf, 0.},
1002             {0.,  0., 1.}
1003         };
1004         applyRotation(mr);
1005     }
1006 
1007 
1008 
1009     public void printRot() {
1010         E.info("rotmat: " + m3xx + " " + m3xy + " " + m3xz);
1011         E.info("        " + m3yx + " " + m3yy + " " + m3yz);
1012         E.info("        " + m3zx + " " + m3zy + " " + m3zz);
1013     }
1014 
1015     public void dragZRotate(int idx, int idy) {
1016         if (m3B == null) return;
1017         double theta = idy / 60.; // ***
1018         zRotate(theta);
1019     }
1020 
1021 
1022     public void dragRollRotate(int idx, int idy) {
1023         if (m3B == null) return;
1024 
1025         double thax = Math.atan2(idx, idy);
1026         double thar =  Math.sqrt(idx*idx + idy*idy) / 60.;  // ***
1027         axisRotate(thax, thar);
1028     }
1029 
1030 
1031     public boolean visible3D(double x, double y, double z) {
1032         // TODO Auto-generated method stub
1033         return (Math.abs(1.5 * dpdwx * (xProj(x,y,z) - wcx)) < width &&
1034                 Math.abs(1.5 * dpdwy * (yProj(x,y,z) - wcy)) < height);
1035 
1036     }
1037 
1038 
1039     public double[][] getProjectionMatrix() {
1040         double[][] mat = {{m3xx, m3xy, m3xz}, {m3yx, m3yy, m3yz}, {m3zx, m3zy, m3zz}};
1041         return mat;
1042     }
1043 
1044     public double[] get3Center() {
1045         double[] ret = {w3cx, w3cy, w3cz};
1046         return ret;
1047     }
1048 
1049     public double[] get2Center() {
1050         double[] ret = {w2cx, w2cy, w2cz};
1051         return ret;
1052     }
1053 
1054 
1055 
1056     public void setProjectionMatrix(double[][] pm) {
1057         m3xx = pm[0][0];
1058         m3xy = pm[0][1];
1059         m3xz = pm[0][2];
1060         m3yx = pm[1][0];
1061         m3yy = pm[1][1];
1062         m3yz = pm[1][2];
1063         m3zx = pm[2][0];
1064         m3zy = pm[2][1];
1065         m3zz = pm[2][2];
1066     }
1067 
1068 
1069 
1070     public void set3Center(double[] cen) {
1071         w3cx = cen[0];
1072         w3cy = cen[1];
1073         w3cz = cen[2];
1074     }
1075 
1076 
1077     public void set2Center(double[] cen) {
1078         w2cx = cen[0];
1079         w2cy = cen[1];
1080     }
1081 
1082 
1083     public void setScale(double sf) {
1084         dpdwx = sf;
1085         dpdwy = sf;
1086     }
1087 
1088     public double getScale() {
1089         return Math.sqrt(dpdwx * dpdwy);
1090     }
1091 
1092 }
1093 
1094 
1095 
1096 /*
1097  *
1098  *
1099  *
1100  * public final double[] limits() { return getRange(); }
1101  *
1102  * public final double[] getLimits () { double[] da = getRange(); double[] ada =
1103  * new double[4]; for (int i = 0; i < 4; i++) ada[i] = Math.abs (da[i]); double
1104  * xm = (ada[1] > ada[0] ? ada[1] : ada[0]); double ym = (ada[3] > ada[2] ?
1105  * ada[3] : ada[2]); int px = (int) ((Math.log (xm) / - Math.log (Math.abs
1106  * (da[1] - da[0]))) / Math.log(10.)) + 3; int py = (int) ((Math.log (ym) / -
1107  * Math.log (Math.abs (da[3] - da[2]))) / Math.log(10.)) + 3; da[0] =
1108  * Formatter.trim (da[0], px); da[1] = Formatter.trim (da[1], px); da[2] =
1109  * Formatter.trim (da[2], py); da[3] = Formatter.trim (da[3], py); return da; }
1110  *
1111  *
1112  * public final double[] alims (double[] x, int n) { double a = x[0]; double b =
1113  * x[0]; for (int i = 0; i < n; i++) { if (x[i] < a) a = x[i]; if (x[i] > b) b =
1114  * x[i]; } if (a >= b) { a -= 0.5; b += 0.5; } double[] d = {a, b}; return d; }
1115  *
1116  * public final void setRangeToFrameData (double[] x, double[] y, int n) {
1117  * double[] dx = alims (x, n); double[] dy = alims (y, n); setLimits (dx[0],
1118  * dx[1], dy[0], dy[1]); }
1119  *
1120  *
1121  *  } }
1122  *
1123  *
1124  *
1125  *
1126  * public final void forceLimits (double xl, double xh, double yl, double yh) {
1127  * if (xl > xh) { double t = xl; xl = xh; xh = t; } if (yl > yh) { double t =
1128  * yl; yl = yh; yh = t; }
1129  *
1130  * boolean bxr = xRescalable; xRescalable = true; boolean byr = yRescalable;
1131  * yRescalable = true;
1132  *
1133  * setXrange (xl, xh); setYrange (yl, yh); xRescalable = bxr; yRescalable = byr;
1134  * if (constantAspectRatio) enforceAspectRatioY(); }
1135  *
1136  *
1137  * public final void setLimits (double[] dd) { if (dd == null || dd.length < 4)
1138  * return; setLimits (dd[0], dd[1], dd[2], dd[3]); } public final void
1139  * forceLimits (double[] dd) { if (dd == null || dd.length < 4) return;
1140  * forceLimits (dd[0], dd[1], dd[2], dd[3]); }
1141  *
1142  *  // NB following section contains only occurences of dpdwx
1143  *
1144  *
1145  *
1146  * public final void recordLimits () { double[] bufl = new double[4]; for (int i =
1147  * 0; i < 4; i++) bufl[i] = lastLimits[i];
1148  *
1149  * lastLimits[0] = wcx - hx / dpdwx; lastLimits[1] = wcx + hx / dpdwx;
1150  * lastLimits[2] = wcy - hy / dpdwy; lastLimits[3] = wcy + hy / dpdwy;
1151  *  }
1152  *
1153  *
1154  *
1155  * public final void gdcSetSize (int w, int h) { width = w; height = h; hx =
1156  * (width - leftMargin - rightMargin) / 2; hy = (height - topMargin -
1157  * bottomMargin) / 2; if (hx < 2) hx = 2; if (hy < 2) hy = 2;
1158  *
1159  * pcx = leftMargin + hx; pcy = bottomMargin + hy; }
1160  *
1161  *  }
1162  *
1163  */
1164 
1165 
1166