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
49 private double vxmin;
50 private double vxmax;
51 private double vymin;
52 private double vymax;
53
54
55
56
57
58
59 private boolean trialPanning = false;
60 private double wcxtp;
61 private double wcytp;
62
63
64
65
66
67
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;
73
74
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
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
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
220
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);
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
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
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
533
534
535
536
537
538
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
561
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
628
629
630
631
632
633
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
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
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
795
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
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
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
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
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
978
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
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
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166