comparison src/graphics.cc @ 7427:65f0a8ced9d2

[project @ 2008-01-28 22:42:18 by jwe]
author jwe
date Mon, 28 Jan 2008 22:44:46 +0000
parents f62fb98f1da2
children 464a55f1a5c2
comparison
equal deleted inserted replaced
7426:b9df9abdffbb 7427:65f0a8ced9d2
140 retval(1) = 1; 140 retval(1) = 1;
141 141
142 return retval; 142 return retval;
143 } 143 }
144 144
145 static Matrix
146 default_axes_position (void)
147 {
148 Matrix m (1, 4, 0.0);
149 m(0) = 0.13;
150 m(1) = 0.11;
151 m(2) = 0.775;
152 m(3) = 0.815;
153 return m;
154 }
155
156 static Matrix
157 default_axes_outerposition (void)
158 {
159 Matrix m (1, 4, 0.0);
160 m(2) = m(3) = 1.0;
161 return m;
162 }
163
145 // NOTE: "cb" is passed by value, because "function_value" method 164 // NOTE: "cb" is passed by value, because "function_value" method
146 // is non-const; passing "cb" by const-reference is not 165 // is non-const; passing "cb" by const-reference is not
147 // possible 166 // possible
148 167
149 static void 168 static void
196 215
197 if (! error_state) 216 if (! error_state)
198 feval (fcn, args); 217 feval (fcn, args);
199 218
200 END_INTERRUPT_WITH_EXCEPTIONS; 219 END_INTERRUPT_WITH_EXCEPTIONS;
220 }
221
222 static Matrix
223 convert_position (const Matrix& pos, const caseless_str& from_units,
224 const caseless_str& to_units,
225 const Matrix& parent_dim = Matrix (1, 2, 0.0),
226 const graphics_backend& backend = graphics_backend ())
227 {
228 Matrix retval (1, 4);
229 double res = 0;
230
231 if (from_units.compare ("pixels"))
232 retval = pos;
233 else if (from_units.compare ("normalized"))
234 {
235 retval(0) = pos(0) * parent_dim(0) + 1;
236 retval(1) = pos(1) * parent_dim(1) + 1;
237 retval(2) = pos(2) * parent_dim(0);
238 retval(3) = pos(3) * parent_dim(1);
239 }
240 else if (from_units.compare ("characters"))
241 {
242 // FIXME: implement this
243 }
244 else
245 {
246 res = backend.get_screen_resolution ();
247
248 double f = 0.0;
249
250 if (from_units.compare ("points"))
251 f = res / 72.0;
252 else if (from_units.compare ("inches"))
253 f = res;
254 else if (from_units.compare ("centimeters"))
255 f = res / 2.54;
256
257 if (f > 0)
258 {
259 retval(0) = pos(0) * f + 1;
260 retval(1) = pos(1) * f + 1;
261 retval(2) = pos(2) * f;
262 retval(3) = pos(3) * f;
263 }
264 }
265
266 if (! to_units.compare ("pixels"))
267 {
268 if (to_units.compare ("normalized"))
269 {
270 retval(0) = (retval(0) - 1) / parent_dim(0);
271 retval(1) = (retval(1) - 1) / parent_dim(1);
272 retval(2) /= parent_dim(0);
273 retval(3) /= parent_dim(1);
274 }
275 else if (to_units.compare ("characters"))
276 {
277 // FIXME: implement this
278 }
279 else
280 {
281 if (res <= 0)
282 res = backend.get_screen_resolution ();
283
284 double f = 0.0;
285
286 if (to_units.compare ("points"))
287 f = res / 72.0;
288 else if (to_units.compare ("inches"))
289 f = res;
290 else if (to_units.compare ("centimeters"))
291 f = res / 2.54;
292
293 if (f > 0)
294 {
295 retval(0) = (retval(0) - 1) / f;
296 retval(1) = (retval(1) - 1) / f;
297 retval(2) /= f;
298 retval(3) /= f;
299 }
300 }
301 }
302
303 return retval;
201 } 304 }
202 305
203 // --------------------------------------------------------------------- 306 // ---------------------------------------------------------------------
204 307
205 radio_values::radio_values (const std::string& opt_string) 308 radio_values::radio_values (const std::string& opt_string)
1206 args(0) = fh.as_octave_value (); 1309 args(0) = fh.as_octave_value ();
1207 feval ("gnuplot_drawnow", args); 1310 feval ("gnuplot_drawnow", args);
1208 } 1311 }
1209 1312
1210 Matrix get_canvas_size (const graphics_handle&) const 1313 Matrix get_canvas_size (const graphics_handle&) const
1211 { return Matrix (1, 2, 0.0); } 1314 {
1315 Matrix sz (1, 2, 0.0);
1316 return sz;
1317 }
1318
1319 double get_screen_resolution (void) const
1320 { return 72.0; }
1212 }; 1321 };
1213 1322
1214 graphics_backend 1323 graphics_backend
1215 graphics_backend::default_backend (void) 1324 graphics_backend::default_backend (void)
1216 { 1325 {
1363 1472
1364 void 1473 void
1365 axes::properties::set_defaults (base_graphics_object& obj, 1474 axes::properties::set_defaults (base_graphics_object& obj,
1366 const std::string& mode) 1475 const std::string& mode)
1367 { 1476 {
1368 position = Matrix (); 1477 position = default_axes_position ();
1369 title = graphics_handle (); 1478 title = graphics_handle ();
1370 box = "on"; 1479 box = "on";
1371 key = "off"; 1480 key = "off";
1372 keybox = "off"; 1481 keybox = "off";
1373 keypos = 1.0; 1482 keypos = 1.0;
1422 ydir = "normal"; 1531 ydir = "normal";
1423 zdir = "normal"; 1532 zdir = "normal";
1424 yaxislocation = "left"; 1533 yaxislocation = "left";
1425 xaxislocation = "bottom"; 1534 xaxislocation = "bottom";
1426 1535
1536 // Note: camera properties will be set through update_transform
1537 camerapositionmode = "auto";
1538 cameratargetmode = "auto";
1539 cameraupvectormode = "auto";
1540 cameraviewanglemode = "auto";
1541 plotboxaspectratio = Matrix (1, 3, 1.0);
1542 drawmode = "normal";
1543 fontangle = "normal";
1544 fontname = "Helvetica";
1545 fontsize = 12;
1546 fontunits = "points";
1547 fontweight = "normal";
1548 gridlinestyle = "-";
1549 linestyleorder = "-";
1550 linewidth = 0.5;
1551 minorgridlinestyle = "-";
1552 // Note: plotboxaspectratio will be set through update_aspectratiors
1553 plotboxaspectratiomode = "auto";
1554 projection = "orthographic";
1555 tickdir = "in";
1556 tickdirmode = "auto";
1557 ticklength = Matrix (1, 2, 0.1);
1558 tightinset = Matrix (1, 4, 0.0);
1559
1560 sx = "linear";
1561 sy = "linear";
1562 sz = "linear";
1563
1427 Matrix tview (1, 2, 0.0); 1564 Matrix tview (1, 2, 0.0);
1428 tview(1) = 90; 1565 tview(1) = 90;
1429 view = tview; 1566 view = tview;
1430 1567
1431 visible = "on"; 1568 visible = "on";
1446 __colorbar__ = "none"; 1583 __colorbar__ = "none";
1447 1584
1448 delete_children (); 1585 delete_children ();
1449 1586
1450 children = Matrix (); 1587 children = Matrix ();
1588
1589 update_transform ();
1451 1590
1452 override_defaults (obj); 1591 override_defaults (obj);
1453 } 1592 }
1454 1593
1455 graphics_handle 1594 graphics_handle
1510 1649
1511 gh_manager::free (title.handle_value ()); 1650 gh_manager::free (title.handle_value ());
1512 gh_manager::free (xlabel.handle_value ()); 1651 gh_manager::free (xlabel.handle_value ());
1513 gh_manager::free (ylabel.handle_value ()); 1652 gh_manager::free (ylabel.handle_value ());
1514 gh_manager::free (zlabel.handle_value ()); 1653 gh_manager::free (zlabel.handle_value ());
1654 }
1655
1656 inline Matrix
1657 xform_matrix (void)
1658 {
1659 Matrix m (4, 4, 0.0);
1660 for (int i = 0; i < 4; i++)
1661 m(i,i) = 1;
1662 return m;
1663 }
1664
1665 inline ColumnVector
1666 xform_vector (void)
1667 {
1668 ColumnVector v (4, 0.0);
1669 v(3) = 1;
1670 return v;
1671 }
1672
1673 inline ColumnVector
1674 xform_vector (double x, double y, double z)
1675 {
1676 ColumnVector v (4, 1.0);
1677 v(0) = x; v(1) = y; v(2) = z;
1678 return v;
1679 }
1680
1681 inline ColumnVector
1682 transform (const Matrix& m, double x, double y, double z)
1683 {
1684 return (m * xform_vector (x, y, z));
1685 }
1686
1687 inline Matrix
1688 xform_scale (double x, double y, double z)
1689 {
1690 Matrix m (4, 4, 0.0);
1691 m(0,0) = x; m(1,1) = y; m(2,2) = z; m(3,3) = 1;
1692 return m;
1693 }
1694
1695 inline Matrix
1696 xform_translate (double x, double y, double z)
1697 {
1698 Matrix m = xform_matrix ();
1699 m(0,3) = x; m(1,3) = y; m(2,3) = z; m(3,3) = 1;
1700 return m;
1701 }
1702
1703 inline void
1704 scale (Matrix& m, double x, double y, double z)
1705 {
1706 m = m * xform_scale (x, y, z);
1707 }
1708
1709 inline void
1710 translate (Matrix& m, double x, double y, double z)
1711 {
1712 m = m * xform_translate (x, y, z);
1713 }
1714
1715 inline void
1716 xform (ColumnVector& v, const Matrix& m)
1717 {
1718 v = m*v;
1719 }
1720
1721 inline void
1722 scale (ColumnVector& v, double x, double y, double z)
1723 {
1724 v(0) *= x;
1725 v(1) *= y;
1726 v(2) *= z;
1727 }
1728
1729 inline void
1730 translate (ColumnVector& v, double x, double y, double z)
1731 {
1732 v(0) += x;
1733 v(1) += y;
1734 v(2) += z;
1735 }
1736
1737 inline void
1738 normalize (ColumnVector& v)
1739 {
1740 double fact = 1.0/sqrt(v(0)*v(0)+v(1)*v(1)+v(2)*v(2));
1741 scale (v, fact, fact, fact);
1742 }
1743
1744 inline double
1745 dot (const ColumnVector& v1, const ColumnVector& v2)
1746 {
1747 return (v1(0)*v2(0)+v1(1)*v2(1)+v1(2)*v2(2));
1748 }
1749
1750 inline double
1751 norm (const ColumnVector& v)
1752 {
1753 return sqrt (dot (v, v));
1754 }
1755
1756 inline ColumnVector
1757 cross (const ColumnVector& v1, const ColumnVector& v2)
1758 {
1759 ColumnVector r = xform_vector ();
1760 r(0) = v1(1)*v2(2)-v1(2)*v2(1);
1761 r(1) = v1(2)*v2(0)-v1(0)*v2(2);
1762 r(2) = v1(0)*v2(1)-v1(1)*v2(0);
1763 return r;
1764 }
1765
1766 inline Matrix
1767 unit_cube (void)
1768 {
1769 static double data[32] = {
1770 0,0,0,1,
1771 1,0,0,1,
1772 0,1,0,1,
1773 0,0,1,1,
1774 1,1,0,1,
1775 1,0,1,1,
1776 0,1,1,1,
1777 1,1,1,1};
1778 Matrix m (4, 8);
1779 memcpy (m.fortran_vec (), data, sizeof(double)*32);
1780 return m;
1781 }
1782
1783 inline ColumnVector
1784 cam2xform (const Array<double>& m)
1785 {
1786 ColumnVector retval (4, 1.0);
1787 memcpy (retval.fortran_vec (), m.fortran_vec (), sizeof(double)*3);
1788 return retval;
1789 }
1790
1791 inline RowVector
1792 xform2cam (const ColumnVector& v)
1793 {
1794 return v.extract_n (0, 3).transpose ();
1795 }
1796
1797 void
1798 axes::properties::update_camera (void)
1799 {
1800 double xd = (xdir_is ("normal") ? 1 : -1);
1801 double yd = (ydir_is ("normal") ? 1 : -1);
1802 double zd = (zdir_is ("normal") ? 1 : -1);
1803
1804 Matrix xlim = sx.scale (get_xlim ().matrix_value ());
1805 Matrix ylim = sy.scale (get_ylim ().matrix_value ());
1806 Matrix zlim = sz.scale (get_zlim ().matrix_value ());
1807
1808 double xo = xlim(xd > 0 ? 0 : 1);
1809 double yo = ylim(yd > 0 ? 0 : 1);
1810 double zo = zlim(zd > 0 ? 0 : 1);
1811
1812 Matrix pb = get_plotboxaspectratio ().matrix_value ();
1813
1814 bool autocam = (camerapositionmode_is ("auto")
1815 && cameratargetmode_is ("auto")
1816 && cameraupvectormode_is ("auto")
1817 && cameraviewanglemode_is ("auto"));
1818 bool dowarp = (autocam && dataaspectratiomode_is("auto")
1819 && plotboxaspectratiomode_is ("auto"));
1820
1821 ColumnVector c_eye (xform_vector ());
1822 ColumnVector c_center (xform_vector ());
1823 ColumnVector c_upv (xform_vector ());
1824
1825 if (cameratargetmode_is ("auto"))
1826 {
1827 c_center(0) = (xlim(0)+xlim(1))/2;
1828 c_center(1) = (ylim(0)+ylim(1))/2;
1829 c_center(2) = (zlim(0)+zlim(1))/2;
1830
1831 cameratarget = xform2cam (c_center);
1832 }
1833 else
1834 c_center = cam2xform (get_cameratarget ().matrix_value ());
1835
1836 if (camerapositionmode_is ("auto"))
1837 {
1838 Matrix view = get_view ().matrix_value ();
1839 double az = view(0), el = view(1);
1840 double d = 5*sqrt(pb(0)*pb(0)+pb(1)*pb(1)+pb(2)*pb(2));
1841
1842 if (el == 90 || el == -90)
1843 c_eye(2) = d*signum(el);
1844 else
1845 {
1846 az *= M_PI/180.0;
1847 el *= M_PI/180.0;
1848 c_eye(0) = d*cos(el)*sin(az);
1849 c_eye(1) = -d*cos(el)*cos(az);
1850 c_eye(2) = d*sin(el);
1851 }
1852 c_eye(0) = c_eye(0)*(xlim(1)-xlim(0))/(xd*pb(0))+c_center(0);
1853 c_eye(1) = c_eye(1)*(ylim(1)-ylim(0))/(yd*pb(1))+c_center(1);
1854 c_eye(2) = c_eye(2)*(zlim(1)-zlim(0))/(zd*pb(2))+c_center(2);
1855
1856 cameraposition = xform2cam (c_eye);
1857 }
1858 else
1859 c_eye = cam2xform (get_cameraposition ().matrix_value ());
1860
1861 if (cameraupvectormode_is ("auto"))
1862 {
1863 Matrix view = get_view ().matrix_value ();
1864 double az = view(0), el = view(1);
1865
1866 if (el == 90 || el == -90)
1867 {
1868 c_upv(0) = -sin(az*M_PI/180.0)*(xlim(1)-xlim(0))/pb(0);
1869 c_upv(1) = cos(az*M_PI/180.0)*(ylim(1)-ylim(0))/pb(1);
1870 }
1871 else
1872 c_upv(2) = 1;
1873
1874 cameraupvector = xform2cam (c_upv);
1875 }
1876 else
1877 c_upv = cam2xform (get_cameraupvector ().matrix_value ());
1878
1879 Matrix x_view = xform_matrix ();
1880 Matrix x_projection = xform_matrix ();
1881 Matrix x_viewport = xform_matrix ();
1882 Matrix x_normrender = xform_matrix ();
1883 Matrix x_pre = xform_matrix ();
1884
1885 x_render = xform_matrix ();
1886 x_render_inv = xform_matrix ();
1887
1888 scale (x_pre, pb(0), pb(1), pb(2));
1889 translate (x_pre, -0.5, -0.5, -0.5);
1890 scale (x_pre, xd/(xlim(1)-xlim(0)), yd/(ylim(1)-ylim(0)),
1891 zd/(zlim(1)-zlim(0)));
1892 translate (x_pre, -xo, -yo, -zo);
1893
1894 xform (c_eye, x_pre);
1895 xform (c_center, x_pre);
1896 scale (c_upv, pb(0)/(xlim(1)-xlim(0)), pb(1)/(ylim(1)-ylim(0)),
1897 pb(2)/(zlim(1)-zlim(0)));
1898 translate (c_center, -c_eye(0), -c_eye(1), -c_eye(2));
1899
1900 ColumnVector F (c_center), f (F), UP (c_upv);
1901 normalize (f);
1902 normalize (UP);
1903
1904 if (abs (dot (f, UP)) > 1e-15)
1905 {
1906 double fa = 1/sqrt(1-f(2)*f(2));
1907 scale (UP, fa, fa, fa);
1908 }
1909
1910 ColumnVector s = cross (f, UP);
1911 ColumnVector u = cross (s, f);
1912
1913 scale (x_view, 1, 1, -1);
1914 Matrix l = xform_matrix ();
1915 l(0,0) = s(0); l(0,1) = s(1); l(0,2) = s(2);
1916 l(1,0) = u(0); l(1,1) = u(1); l(1,2) = u(2);
1917 l(2,0) = -f(0); l(2,1) = -f(1); l(2,2) = -f(2);
1918 x_view = x_view * l;
1919 translate (x_view, -c_eye(0), -c_eye(1), -c_eye(2));
1920 scale (x_view, pb(0), pb(1), pb(2));
1921 translate (x_view, -0.5, -0.5, -0.5);
1922
1923 Matrix x_cube = x_view * unit_cube ();
1924 ColumnVector cmin = x_cube.row_min (), cmax = x_cube.row_max ();
1925 double xM = cmax(0)-cmin(0);
1926 double yM = cmax(1)-cmin(1);
1927
1928 Matrix bb = get_boundingbox ();
1929 Matrix cs = get_backend ().get_canvas_size (__myhandle__);
1930 double fh = cs(1);
1931
1932 double v_angle;
1933
1934 if (cameraviewanglemode_is ("auto"))
1935 {
1936 double af;
1937
1938 // FIXME: Was this really needed? When compared to Matlab, it
1939 // does not seem to be required. Need investigation with concrete
1940 // backend to see results visually.
1941 if (false && dowarp)
1942 af = 1.0 / (xM > yM ? xM : yM);
1943 else
1944 {
1945 if ((bb(2)/bb(3)) > (xM/yM))
1946 af = 1.0 / yM;
1947 else
1948 af = 1.0 / xM;
1949 }
1950 v_angle = 2 * (180.0 / M_PI) * atan (1 / (2 * af * norm (F)));
1951
1952 cameraviewangle = v_angle;
1953 }
1954 else
1955 v_angle = get_cameraviewangle ();
1956
1957 double pf = 1 / (2 * tan ((v_angle / 2) * M_PI / 180.0) * norm (F));
1958 scale (x_projection, pf, pf, 1);
1959
1960 if (dowarp)
1961 {
1962 xM *= pf;
1963 yM *= pf;
1964 translate (x_viewport, bb(0)+bb(2)/2, fh-(bb(1)+bb(3)/2)+1, 0);
1965 scale (x_viewport, bb(2)/xM, -bb(3)/yM, 1);
1966 }
1967 else
1968 {
1969 double pix = 1;
1970 if (autocam)
1971 {
1972 if ((bb(2)/bb(3)) > (xM/yM))
1973 pix = bb(3);
1974 else
1975 pix = bb(2);
1976 }
1977 else
1978 pix = (bb(2) < bb(3) ? bb(2) : bb(3));
1979 translate (x_viewport, bb(0)+bb(2)/2, fh-(bb(1)+bb(3)/2)+1, 0);
1980 scale (x_viewport, pix, -pix, 1);
1981 }
1982
1983 x_normrender = x_viewport * x_projection * x_view;
1984
1985 x_cube = x_normrender * unit_cube ();
1986 cmin = x_cube.row_min ();
1987 cmax = x_cube.row_max ();
1988 x_zlim.resize (1, 2);
1989 x_zlim(0) = cmin(2);
1990 x_zlim(1) = cmax(2);
1991
1992 x_render = x_normrender;
1993 scale (x_render, xd/(xlim(1)-xlim(0)), yd/(ylim(1)-ylim(0)),
1994 zd/(zlim(1)-zlim(0)));
1995 translate (x_render, -xo, -yo, -zo);
1996
1997 x_viewtransform = x_view;
1998 x_projectiontransform = x_projection;
1999 x_viewporttransform = x_viewport;
2000 x_normrendertransform = x_normrender;
2001 x_rendertransform = x_render;
2002
2003 x_render_inv = x_render.inverse ();
2004
2005 // Note: these matrices are a slight modified version of the regular
2006 // matrices, more suited for OpenGL rendering (x_gl_mat1 => light
2007 // => x_gl_mat2)
2008 x_gl_mat1 = x_view;
2009 scale (x_gl_mat1, xd/(xlim(1)-xlim(0)), yd/(ylim(1)-ylim(0)),
2010 zd/(zlim(1)-zlim(0)));
2011 translate (x_gl_mat1, -xo, -yo, -zo);
2012 x_gl_mat2 = x_viewport * x_projection;
2013 }
2014
2015 void
2016 axes::properties::update_aspectratios (void)
2017 {
2018 Matrix xlim = get_xlim ().matrix_value ();
2019 Matrix ylim = get_ylim ().matrix_value ();
2020 Matrix zlim = get_zlim ().matrix_value ();
2021
2022 double dx = (xlim(1)-xlim(0));
2023 double dy = (ylim(1)-ylim(0));
2024 double dz = (zlim(1)-zlim(0));
2025
2026 if (dataaspectratiomode_is ("auto"))
2027 {
2028 double dmin = xmin (xmin (dx, dy), dz);
2029 Matrix da (1, 3, 0.0);
2030
2031 da(0) = dx/dmin;
2032 da(1) = dy/dmin;
2033 da(2) = dz/dmin;
2034
2035 dataaspectratio = da;
2036 }
2037
2038 if (plotboxaspectratiomode_is ("auto"))
2039 {
2040 if (dataaspectratiomode_is ("auto"))
2041 plotboxaspectratio = Matrix (1, 3, 1.0);
2042 else
2043 {
2044 Matrix da = get_dataaspectratio ().matrix_value ();
2045 Matrix pba (1, 3, 0.0);
2046
2047 pba(0) = dx/da(0);
2048 pba(1) = dy/da(1);
2049 pba(2) = dz/da(2);
2050 }
2051 }
2052
2053 // FIXME: if plotboxaspectratiomode is "manual", limits
2054 // and/or dataaspectratio might be adapted
2055 }
2056
2057 Matrix
2058 axes::properties::get_boundingbox (void) const
2059 {
2060 graphics_backend b = get_backend ();
2061 Matrix pos;
2062
2063 pos = convert_position (get_position ().matrix_value (), get_units (),
2064 "pixels", b.get_canvas_size (__myhandle__), b);
2065 pos(0)--;
2066 pos(1)--;
2067
2068 return pos;
1515 } 2069 }
1516 2070
1517 octave_value 2071 octave_value
1518 axes::get_default (const caseless_str& name) const 2072 axes::get_default (const caseless_str& name) const
1519 { 2073 {
1775 break; 2329 break;
1776 2330
1777 default: 2331 default:
1778 break; 2332 break;
1779 } 2333 }
2334
2335 xproperties.update_transform ();
1780 2336
1781 unwind_protect::run (); 2337 unwind_protect::run ();
1782 } 2338 }
1783 2339
1784 // --------------------------------------------------------------------- 2340 // ---------------------------------------------------------------------