The R Project SVN R

Rev

Rev 59177 | Rev 59267 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 59177 Rev 59258
Line 1... Line 1...
1
/*
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
4
 *  Copyright (C) 1997--2011  The R Core Team
4
 *  Copyright (C) 1997--2012  The R Core Team
5
 *
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
9
 *  (at your option) any later version.
Line 29... Line 29...
29
#include <Graphics.h>
29
#include <Graphics.h>
30
#include <Colors.h> /* for isNAcol */
30
#include <Colors.h> /* for isNAcol */
31
#include <Print.h>
31
#include <Print.h>
32
#include <R_ext/Boolean.h>
32
#include <R_ext/Boolean.h>
33
 
33
 
34
/* Conversion of degrees to radians */
-
 
35
 
-
 
36
#define DegToRad(x) (DEG2RAD * x)
-
 
37
 
-
 
38
/* Definitions of data structures for vectors and */
-
 
39
/* transformations in homogeneous 3d coordinates */
34
/* filled contours and perspective plots were originally here,
40
 
-
 
41
typedef double Vector3d[4];
-
 
42
typedef double Trans3d[4][4];
-
 
43
 
-
 
44
/* The viewing transformation matrix. */
-
 
45
 
-
 
46
static SEXP gcall;
-
 
47
static Trans3d VT;
-
 
48
 
-
 
49
static void TransVector (Vector3d u, Trans3d T, Vector3d v)
-
 
50
{
-
 
51
    double sum;
-
 
52
    int i, j;
-
 
53
 
-
 
54
    for (i = 0; i < 4; i++) {
-
 
55
	sum = 0;
-
 
56
	for (j = 0; j < 4; j++)
-
 
57
	    sum = sum + u[j] * T[j][i];
-
 
58
	v[i] = sum;
-
 
59
    }
-
 
60
}
-
 
61
 
-
 
62
static void Accumulate (Trans3d T)
-
 
63
{
-
 
64
    Trans3d U;
-
 
65
    double sum;
-
 
66
    int i, j, k;
-
 
67
 
-
 
68
    for (i = 0; i < 4; i++) {
-
 
69
	for (j = 0; j < 4; j++) {
-
 
70
	    sum = 0;
-
 
71
	    for (k = 0; k < 4; k++)
-
 
72
		sum = sum + VT[i][k] * T[k][j];
-
 
73
	    U[i][j] = sum;
-
 
74
	}
-
 
75
    }
-
 
76
    for (i = 0; i < 4; i++)
-
 
77
	for (j = 0; j < 4; j++)
-
 
78
	    VT[i][j] = U[i][j];
-
 
79
}
-
 
80
 
-
 
81
static void SetToIdentity (Trans3d T)
-
 
82
{
-
 
83
    int i, j;
-
 
84
    for (i = 0; i < 4; i++) {
35
   now in graphics/src/plot3d.c .
85
	for (j = 0; j < 4; j++)
-
 
86
	    T[i][j] = 0;
-
 
87
	T[i][i] = 1;
-
 
88
    }
36
 */
89
}
-
 
90
 
-
 
91
static void Translate (double x, double y, double z)
-
 
92
{
-
 
93
    Trans3d T;
-
 
94
    SetToIdentity(T);
-
 
95
    T[3][0] = x;
-
 
96
    T[3][1] = y;
-
 
97
    T[3][2] = z;
-
 
98
    Accumulate(T);
-
 
99
}
-
 
100
 
-
 
101
static void Scale (double x, double y, double z)
-
 
102
{
-
 
103
    Trans3d T;
-
 
104
    SetToIdentity(T);
-
 
105
    T[0][0] = x;
-
 
106
    T[1][1] = y;
-
 
107
    T[2][2] = z;
-
 
108
    Accumulate(T);
-
 
109
}
-
 
110
 
-
 
111
static void XRotate (double angle)
-
 
112
{
-
 
113
    double c, s;
-
 
114
    Trans3d T;
-
 
115
    SetToIdentity(T);
-
 
116
    c = cos(DegToRad(angle));
-
 
117
    s = sin(DegToRad(angle));
-
 
118
    T[1][1] = c;
-
 
119
    T[2][1] = -s;
-
 
120
    T[2][2] = c;
-
 
121
    T[1][2] = s;
-
 
122
    Accumulate(T);
-
 
123
}
-
 
124
 
-
 
125
static void YRotate (double angle)
-
 
126
{
-
 
127
    double c, s;
-
 
128
    Trans3d T;
-
 
129
    SetToIdentity(T);
-
 
130
    c = cos(DegToRad(angle));
-
 
131
    s = sin(DegToRad(angle));
-
 
132
    T[0][0] = c;
-
 
133
    T[2][0] = s;
-
 
134
    T[2][2] = c;
-
 
135
    T[0][2] = -s;
-
 
136
    Accumulate(T);
-
 
137
}
-
 
138
 
-
 
139
static void ZRotate (double angle)
-
 
140
{
-
 
141
    double c, s;
-
 
142
    Trans3d T;
-
 
143
    SetToIdentity(T);
-
 
144
    c = cos(DegToRad(angle));
-
 
145
    s = sin(DegToRad(angle));
-
 
146
    T[0][0] = c;
-
 
147
    T[1][0] = -s;
-
 
148
    T[1][1] = c;
-
 
149
    T[0][1] = s;
-
 
150
    Accumulate(T);
-
 
151
}
-
 
152
 
-
 
153
static void Perspective (double d)
-
 
154
{
-
 
155
    Trans3d T;
-
 
156
 
-
 
157
    SetToIdentity(T);
-
 
158
    T[2][3] = -1 / d;
-
 
159
    Accumulate(T);
-
 
160
}
-
 
161
 
-
 
162
 
37
 
163
/* Stuff for labels on contour plots
38
/* Stuff for labels on contour plots
164
   Originally written by Nicholas Hildreth
39
   Originally written by Nicholas Hildreth
165
   Adapted by Paul Murrell
40
   Adapted by Paul Murrell
166
*/
41
*/
Line 764... Line 639...
764
 * Given nx x values, ny y values, nx*ny z values,
639
 * Given nx x values, ny y values, nx*ny z values,
765
 * and nl cut-values in z ...
640
 * and nl cut-values in z ...
766
 * ... produce a list of contour lines:
641
 * ... produce a list of contour lines:
767
 *   list of sub-lists
642
 *   list of sub-lists
768
 *     sub-list = x vector, y vector, and cut-value.
643
 *     sub-list = x vector, y vector, and cut-value.
769
 
-
 
770
 * Apart from here, used in package clines.
-
 
771
 */
644
 */
772
SEXP GEcontourLines(double *x, int nx, double *y, int ny,
645
SEXP GEcontourLines(double *x, int nx, double *y, int ny,
773
		    double *z, double *levels, int nl)
646
		    double *z, double *levels, int nl)
774
{
647
{
775
    const void *vmax;
648
    const void *vmax;
Line 1510... Line 1383...
1510
    /* NOTE: on replay, call == R_NilValue */
1383
    /* NOTE: on replay, call == R_NilValue */
1511
    if (GRecording(call, dd))
1384
    if (GRecording(call, dd))
1512
	GErecordGraphicOperation(op, oargs, dd);
1385
	GErecordGraphicOperation(op, oargs, dd);
1513
    return result;
1386
    return result;
1514
}
1387
}
1515
 
-
 
1516
 
-
 
1517
	/*  F i l l e d   C o n t o u r   P l o t s  */
-
 
1518
 
-
 
1519
	/*  R o s s  I h a k a,  M a r c h  1 9 9 9  */
-
 
1520
 
-
 
1521
static void
-
 
1522
FindCutPoints(double low, double high,
-
 
1523
	      double x1, double y1, double z1,
-
 
1524
	      double x2, double y2, double z2,
-
 
1525
	      double *x, double *y, double *z,
-
 
1526
	      int *npt)
-
 
1527
{
-
 
1528
    double c;
-
 
1529
 
-
 
1530
    if (z1 > z2 ) {
-
 
1531
	if (z2 > high || z1 < low) return;
-
 
1532
	if (z1 < high) {
-
 
1533
	    x[*npt] = x1;
-
 
1534
	    y[*npt] = y1;
-
 
1535
	    z[*npt] = z1;
-
 
1536
	    ++*npt;
-
 
1537
	} else if (z1 == R_PosInf) {
-
 
1538
	    x[*npt] = x2;
-
 
1539
	    y[*npt] = y1;
-
 
1540
	    z[*npt] = z2;
-
 
1541
	    ++*npt;
-
 
1542
	} else { /* z1 >= high, z2 in range */
-
 
1543
	    c = (z1 - high) / (z1 - z2);
-
 
1544
	    x[*npt] = x1 + c * (x2 - x1);
-
 
1545
	    y[*npt] = y1;
-
 
1546
	    z[*npt] = z1 + c * (z2 - z1);
-
 
1547
	    ++*npt;
-
 
1548
	}
-
 
1549
	if (z2 == R_NegInf) {
-
 
1550
	    x[*npt] = x1;
-
 
1551
	    y[*npt] = y1;
-
 
1552
	    z[*npt] = z1;
-
 
1553
	    ++*npt;
-
 
1554
	} else if (z2 <= low) { /* and z1 in range */
-
 
1555
	    c = (z2 -low) / (z2 - z1);
-
 
1556
	    x[*npt] = x2 - c * (x2 - x1);
-
 
1557
	    y[*npt] = y1;
-
 
1558
	    z[*npt] = z2 - c * (z2 - z1);
-
 
1559
	    ++*npt;
-
 
1560
	}
-
 
1561
    } else if (z1 < z2) {
-
 
1562
	if (z2 < low || z1 > high) return;
-
 
1563
	if (z1 > low) {
-
 
1564
	    x[*npt] = x1;
-
 
1565
	    y[*npt] = y1;
-
 
1566
	    z[*npt] = z1;
-
 
1567
	    ++*npt;
-
 
1568
	} else if (z1 == R_NegInf) {
-
 
1569
	    x[*npt] = x2;
-
 
1570
	    y[*npt] = y1;
-
 
1571
	    z[*npt] = z2;;
-
 
1572
	    ++*npt;
-
 
1573
	} else { /* and z2 in range */
-
 
1574
	    c = (z1 - low) / (z1 - z2);
-
 
1575
	    x[*npt] = x1 + c * (x2 - x1);
-
 
1576
	    y[*npt] = y1;
-
 
1577
	    z[*npt] = z1 + c * (z2 - z1);
-
 
1578
	    ++*npt;
-
 
1579
	}
-
 
1580
	if (z2 < high) {
-
 
1581
#ifdef OMIT
-
 
1582
	    /* Don't repeat corner vertices */
-
 
1583
	    x[*npt] = x2;
-
 
1584
	    y[*npt] = y2;
-
 
1585
	    z[*npt] = z2;
-
 
1586
	    ++*npt;
-
 
1587
#endif
-
 
1588
	} else if (z2 == R_PosInf) {
-
 
1589
	    x[*npt] = x1;
-
 
1590
	    y[*npt] = y1;
-
 
1591
	    z[*npt] = z1;
-
 
1592
	    ++*npt;
-
 
1593
	} else { /* z2 high, z1 in range */
-
 
1594
	    c = (z2 - high) / (z2 - z1);
-
 
1595
	    x[*npt] = x2 - c * (x2 - x1);
-
 
1596
	    y[*npt] = y1;
-
 
1597
	    z[*npt] = z2 - c * (z2 - z1);
-
 
1598
	    ++*npt;
-
 
1599
	}
-
 
1600
    } else {
-
 
1601
	if(low <= z1 && z1 <= high) {
-
 
1602
	    x[*npt] = x1;
-
 
1603
	    y[*npt] = y1;
-
 
1604
	    z[*npt] = z1;
-
 
1605
	    ++*npt;
-
 
1606
#ifdef OMIT
-
 
1607
	    /* Don't repeat corner vertices */
-
 
1608
	    x[*npt] = x2;
-
 
1609
	    y[*npt] = y2;
-
 
1610
	    z[*npt] = z2;
-
 
1611
	    ++*npt;
-
 
1612
#endif
-
 
1613
	}
-
 
1614
    }
-
 
1615
}
-
 
1616
 
-
 
1617
/* FIXME - This could pretty easily be adapted to handle NA */
-
 
1618
/* values on the grid.  Just search the diagonals for cutpoints */
-
 
1619
/* instead of the cell sides.  Use the same switch idea as in */
-
 
1620
/* contour above.  There are 5 cases to handle. */
-
 
1621
 
-
 
1622
static void
-
 
1623
FindPolygonVertices(double low, double high,
-
 
1624
		    double x1, double x2, double y1, double y2,
-
 
1625
		    double z11, double z21, double z12, double z22,
-
 
1626
		    double *x, double *y, double *z, int *npt)
-
 
1627
{
-
 
1628
    *npt = 0;
-
 
1629
    FindCutPoints(low, high, x1,  y1,  z11, x2,  y1,  z21, x, y, z, npt);
-
 
1630
    FindCutPoints(low, high, y1,  x2,  z21, y2,  x2,  z22, y, x, z, npt);
-
 
1631
    FindCutPoints(low, high, x2,  y2,  z22, x1,  y2,  z12, x, y, z, npt);
-
 
1632
    FindCutPoints(low, high, y2,  x1,  z12, y1,  x1,  z11, y, x, z, npt);
-
 
1633
}
-
 
1634
 
-
 
1635
/* FIXME: [Code consistency] Use macro for the parallel parts of
-
 
1636
	  do_contour, do_filledcontour & do_image ...
-
 
1637
*/
-
 
1638
 
-
 
1639
/* filledcontour(x, y, z, levels, col) */
-
 
1640
SEXP attribute_hidden do_filledcontour(SEXP call, SEXP op, SEXP args, SEXP env)
-
 
1641
{
-
 
1642
    SEXP oargs, sx, sy, sz, sc, scol;
-
 
1643
    double *x, *y, *z, *c;
-
 
1644
    rcolor *col;
-
 
1645
    int i, j, k, npt, nx, ny, nc, ncol, colsave, xpdsave;
-
 
1646
    double px[8], py[8], pz[8];
-
 
1647
    pGEDevDesc dd = GEcurrentDevice();
-
 
1648
 
-
 
1649
    GCheckState(dd);
-
 
1650
 
-
 
1651
    checkArity(op,args);
-
 
1652
    PrintDefaults(); /* prepare for labelformat */
-
 
1653
    oargs = args;
-
 
1654
 
-
 
1655
    sx = CAR(args);
-
 
1656
    internalTypeCheck(call, sx, REALSXP);
-
 
1657
    nx = LENGTH(sx);
-
 
1658
    args = CDR(args);
-
 
1659
 
-
 
1660
    sy = CAR(args);
-
 
1661
    internalTypeCheck(call, sy, REALSXP);
-
 
1662
    ny = LENGTH(sy);
-
 
1663
    args = CDR(args);
-
 
1664
 
-
 
1665
    sz = CAR(args);
-
 
1666
    internalTypeCheck(call, sz, REALSXP);
-
 
1667
    args = CDR(args);
-
 
1668
 
-
 
1669
    sc = CAR(args);/* levels */
-
 
1670
    internalTypeCheck(call, sc, REALSXP);
-
 
1671
    nc = length(sc);
-
 
1672
    args = CDR(args);
-
 
1673
 
-
 
1674
    if (nx < 2 || ny < 2)
-
 
1675
	error(_("insufficient 'x' or 'y' values"));
-
 
1676
 
-
 
1677
    if (nrows(sz) != nx || ncols(sz) != ny)
-
 
1678
	error(_("dimension mismatch"));
-
 
1679
 
-
 
1680
    if (nc < 1)
-
 
1681
	error(_("no contour values"));
-
 
1682
 
-
 
1683
    PROTECT(scol = FixupCol(CAR(args), R_TRANWHITE));
-
 
1684
    ncol = length(scol);
-
 
1685
 
-
 
1686
    /* Shorthand Pointers */
-
 
1687
 
-
 
1688
    x = REAL(sx);
-
 
1689
    y = REAL(sy);
-
 
1690
    z = REAL(sz);
-
 
1691
    c = REAL(sc);
-
 
1692
    col = (rcolor *) INTEGER(scol);
-
 
1693
 
-
 
1694
    /* Check of grid coordinates */
-
 
1695
    /* We want them to all be finite */
-
 
1696
    /* and in strictly ascending order */
-
 
1697
 
-
 
1698
    if (nx < 1 || ny < 1) goto badxy;
-
 
1699
    if (!R_FINITE(x[0])) goto badxy;
-
 
1700
    if (!R_FINITE(y[0])) goto badxy;
-
 
1701
    for (i = 1; i < nx; i++)
-
 
1702
	if (!R_FINITE(x[i]) || x[i] <= x[i - 1]) goto badxy;
-
 
1703
    for (j = 1; j < ny; j++)
-
 
1704
	if (!R_FINITE(y[j]) || y[j] <= y[j - 1]) goto badxy;
-
 
1705
 
-
 
1706
    /* Check of the contour levels */
-
 
1707
 
-
 
1708
    if (!R_FINITE(c[0])) goto badlev;
-
 
1709
    for (k = 1; k < nc; k++)
-
 
1710
	if (!R_FINITE(c[k]) || c[k] <= c[k - 1]) goto badlev;
-
 
1711
 
-
 
1712
    colsave = gpptr(dd)->col;
-
 
1713
    xpdsave = gpptr(dd)->xpd;
-
 
1714
    /* override par("xpd") and force clipping to plot region */
-
 
1715
    gpptr(dd)->xpd = 0;
-
 
1716
 
-
 
1717
    GMode(1, dd);
-
 
1718
 
-
 
1719
    for (i = 1; i < nx; i++) {
-
 
1720
	for (j = 1; j < ny; j++) {
-
 
1721
	    for (k = 1; k < nc ; k++) {
-
 
1722
		FindPolygonVertices(c[k - 1], c[k],
-
 
1723
				    x[i - 1], x[i],
-
 
1724
				    y[j - 1], y[j],
-
 
1725
				    z[i - 1 + (j - 1) * nx],
-
 
1726
				    z[i + (j - 1) * nx],
-
 
1727
				    z[i - 1 + j * nx],
-
 
1728
				    z[i + j * nx],
-
 
1729
				    px, py, pz, &npt);
-
 
1730
		if (npt > 2)
-
 
1731
		    GPolygon(npt, px, py, USER, col[(k-1) % ncol],
-
 
1732
			     R_TRANWHITE, dd);
-
 
1733
	    }
-
 
1734
	}
-
 
1735
    }
-
 
1736
    GMode(0, dd);
-
 
1737
    gpptr(dd)->col = colsave;
-
 
1738
    gpptr(dd)->xpd = xpdsave;
-
 
1739
    UNPROTECT(1);
-
 
1740
    if (GRecording(call, dd))
-
 
1741
	GErecordGraphicOperation(op, oargs, dd);
-
 
1742
    return R_NilValue;
-
 
1743
 
-
 
1744
 badxy:
-
 
1745
    error(_("invalid x / y values or limits"));
-
 
1746
 badlev:
-
 
1747
    error(_("invalid contour levels: must be strictly increasing"));
-
 
1748
    return R_NilValue;  /* never used; to keep -Wall happy */
-
 
1749
}
-
 
1750
 
-
 
1751
 
-
 
1752
	/*  I m a g e   R e n d e r i n g  */
-
 
1753
 
-
 
1754
 
-
 
1755
/* image(x, y, z, col, breaks) */
-
 
1756
SEXP attribute_hidden do_image(SEXP call, SEXP op, SEXP args, SEXP env)
-
 
1757
{
-
 
1758
    SEXP oargs, sx, sy, sz, sc;
-
 
1759
    double *x, *y;
-
 
1760
    int *z, tmp;
-
 
1761
    unsigned *c;
-
 
1762
    int i, j, nx, ny, nc, xpdsave;
-
 
1763
    rcolor colsave;
-
 
1764
    pGEDevDesc dd = GEcurrentDevice();
-
 
1765
 
-
 
1766
    GCheckState(dd);
-
 
1767
 
-
 
1768
    checkArity(op,args);
-
 
1769
    oargs = args;
-
 
1770
 
-
 
1771
    sx = CAR(args);
-
 
1772
    internalTypeCheck(call, sx, REALSXP);
-
 
1773
    nx = LENGTH(sx);
-
 
1774
    args = CDR(args);
-
 
1775
 
-
 
1776
    sy = CAR(args);
-
 
1777
    internalTypeCheck(call, sy, REALSXP);
-
 
1778
    ny = LENGTH(sy);
-
 
1779
    args = CDR(args);
-
 
1780
 
-
 
1781
    sz = CAR(args);
-
 
1782
    internalTypeCheck(call, sz, INTSXP);
-
 
1783
    args = CDR(args);
-
 
1784
 
-
 
1785
    PROTECT(sc = FixupCol(CAR(args), R_TRANWHITE));
-
 
1786
    nc = LENGTH(sc);
-
 
1787
 
-
 
1788
    /* Shorthand Pointers */
-
 
1789
 
-
 
1790
    x = REAL(sx);
-
 
1791
    y = REAL(sy);
-
 
1792
    z = INTEGER(sz);
-
 
1793
    c = (unsigned*)INTEGER(sc);
-
 
1794
 
-
 
1795
    /* Check of grid coordinates now done in C code */
-
 
1796
 
-
 
1797
    colsave = gpptr(dd)->col;
-
 
1798
    xpdsave = gpptr(dd)->xpd;
-
 
1799
    /* override par("xpd") and force clipping to plot region */
-
 
1800
    gpptr(dd)->xpd = 0;
-
 
1801
 
-
 
1802
    GMode(1, dd);
-
 
1803
 
-
 
1804
    for (i = 0; i < nx - 1 ; i++) {
-
 
1805
	for (j = 0; j < ny - 1; j++) {
-
 
1806
	    tmp = z[i + j * (nx - 1)];
-
 
1807
	    if (tmp >= 0 && tmp < nc && tmp != NA_INTEGER)
-
 
1808
		GRect(x[i], y[j], x[i+1], y[j+1], USER, c[tmp],
-
 
1809
		      R_TRANWHITE, dd);
-
 
1810
	}
-
 
1811
    }
-
 
1812
    GMode(0, dd);
-
 
1813
    gpptr(dd)->col = colsave;
-
 
1814
    gpptr(dd)->xpd = xpdsave;
-
 
1815
    UNPROTECT(1);
-
 
1816
    if (GRecording(call, dd))
-
 
1817
	GErecordGraphicOperation(op, oargs, dd);
-
 
1818
    return R_NilValue;
-
 
1819
}
-
 
1820
 
-
 
1821
	/*  P e r s p e c t i v e   S u r f a c e   P l o t s  */
-
 
1822
 
-
 
1823
 
-
 
1824
/* Set up the light source */
-
 
1825
static double Light[4];
-
 
1826
static double Shade;
-
 
1827
static Rboolean DoLighting;
-
 
1828
 
-
 
1829
static void SetUpLight(double theta, double phi)
-
 
1830
{
-
 
1831
    double u[4];
-
 
1832
    u[0] = 0; u[1] = -1; u[2] = 0; u[3] = 1;
-
 
1833
    SetToIdentity(VT);             /* Initialization */
-
 
1834
    XRotate(-phi);                 /* colatitude rotation */
-
 
1835
    ZRotate(theta);                /* azimuthal rotation */
-
 
1836
    TransVector(u, VT, Light);	   /* transform */
-
 
1837
}
-
 
1838
 
-
 
1839
static double FacetShade(double *u, double *v)
-
 
1840
{
-
 
1841
    double nx, ny, nz, sum;
-
 
1842
    nx = u[1] * v[2] - u[2] * v[1];
-
 
1843
    ny = u[2] * v[0] - u[0] * v[2];
-
 
1844
    nz = u[0] * v[1] - u[1] * v[0];
-
 
1845
    sum = sqrt(nx * nx + ny * ny + nz * nz);
-
 
1846
    if (sum == 0) sum = 1;
-
 
1847
    nx /= sum;
-
 
1848
    ny /= sum;
-
 
1849
    nz /= sum;
-
 
1850
    sum = 0.5 * (nx * Light[0] + ny * Light[1] + nz * Light[2] + 1);
-
 
1851
    return pow(sum, Shade);
-
 
1852
}
-
 
1853
 
-
 
1854
 
-
 
1855
/* For each facet, determine the farthest point from the eye. */
-
 
1856
/* Sorting the facets so that these depths are decreasing */
-
 
1857
/* yields an occlusion compatible ordering. */
-
 
1858
/* Note that we ignore z values when doing this. */
-
 
1859
 
-
 
1860
static void DepthOrder(double *z, double *x, double *y, int nx, int ny,
-
 
1861
		       double *depth, int *indx)
-
 
1862
{
-
 
1863
    int i, ii, j, jj, nx1, ny1;
-
 
1864
    Vector3d u, v;
-
 
1865
    double d;
-
 
1866
    nx1 = nx - 1;
-
 
1867
    ny1 = ny - 1;
-
 
1868
    for (i = 0; i < nx1 * ny1; i++)
-
 
1869
	indx[i] = i;
-
 
1870
    for (i = 0; i < nx1; i++)
-
 
1871
	for (j = 0; j < ny1; j++) {
-
 
1872
	    d = -DBL_MAX;
-
 
1873
	    for (ii = 0; ii <= 1; ii++)
-
 
1874
		for (jj = 0; jj <= 1; jj++) {
-
 
1875
		    u[0] = x[i + ii];
-
 
1876
		    u[1] = y[j + jj];
-
 
1877
		    /* Originally I had the following line here: */
-
 
1878
		    /* u[2] = z[i+ii+(j+jj)*nx]; */
-
 
1879
		    /* But this leads to artifacts. */
-
 
1880
		    /* It has been replaced by the following line: */
-
 
1881
		    u[2] = 0;
-
 
1882
		    u[3] = 1;
-
 
1883
		    if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
-
 
1884
			TransVector(u, VT, v);
-
 
1885
			if (v[3] > d) d = v[3];
-
 
1886
		    }
-
 
1887
		}
-
 
1888
	    depth[i+j*nx1] = -d;
-
 
1889
 
-
 
1890
	}
-
 
1891
    /* Determine the depth ordering of the facets to ensure
-
 
1892
       that they are drawn in an occlusion compatible order. */
-
 
1893
    rsort_with_index(depth, indx, nx1 * ny1);
-
 
1894
}
-
 
1895
 
-
 
1896
 
-
 
1897
static void DrawFacets(double *z, double *x, double *y, int nx, int ny,
-
 
1898
		       int *indx, double xs, double ys, double zs,
-
 
1899
		       int *col, int ncol, int border)
-
 
1900
{
-
 
1901
    double xx[4], yy[4], shade = 0;
-
 
1902
    Vector3d u, v;
-
 
1903
    int i, j, k, n, nx1, ny1, icol, nv;
-
 
1904
    unsigned int newcol, r, g, b;
-
 
1905
    pGEDevDesc dd;
-
 
1906
    dd = GEcurrentDevice();
-
 
1907
    nx1 = nx - 1;
-
 
1908
    ny1 = ny - 1;
-
 
1909
    n = nx1 * ny1;
-
 
1910
    for (k = 0; k < n; k++) {
-
 
1911
	nv = 0;
-
 
1912
	i = indx[k] % nx1;
-
 
1913
	j = indx[k] / nx1;
-
 
1914
	icol = (i + j * nx1) % ncol;
-
 
1915
	if (DoLighting) {
-
 
1916
	    /* Note we must scale here */
-
 
1917
	    u[0] = xs * (x[i+1] - x[i]);
-
 
1918
	    u[1] = ys * (y[j] - y[j+1]);
-
 
1919
	    u[2] = zs * (z[(i+1)+j*nx] - z[i+(j+1)*nx]);
-
 
1920
	    v[0] = xs * (x[i+1] - x[i]);
-
 
1921
	    v[1] = ys * (y[j+1] - y[j]);
-
 
1922
	    v[2] = zs * (z[(i+1)+(j+1)*nx] - z[i+j*nx]);
-
 
1923
	    shade = FacetShade(u, v);
-
 
1924
	}
-
 
1925
	u[0] = x[i]; u[1] = y[j];
-
 
1926
	u[2] = z[i + j * nx]; u[3] = 1;
-
 
1927
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
-
 
1928
	    TransVector(u, VT, v);
-
 
1929
	    xx[nv] = v[0] / v[3];
-
 
1930
	    yy[nv] = v[1] / v[3];
-
 
1931
	    nv++;
-
 
1932
	}
-
 
1933
 
-
 
1934
	u[0] = x[i + 1]; u[1] = y[j];
-
 
1935
	u[2] = z[i + 1 + j * nx]; u[3] = 1;
-
 
1936
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
-
 
1937
	    TransVector(u, VT, v);
-
 
1938
	    xx[nv] = v[0] / v[3];
-
 
1939
	    yy[nv] = v[1] / v[3];
-
 
1940
	    nv++;
-
 
1941
	}
-
 
1942
 
-
 
1943
	u[0] = x[i + 1]; u[1] = y[j + 1];
-
 
1944
	u[2] = z[i + 1 + (j + 1) * nx]; u[3] = 1;
-
 
1945
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
-
 
1946
	    TransVector(u, VT, v);
-
 
1947
	    xx[nv] = v[0] / v[3];
-
 
1948
	    yy[nv] = v[1] / v[3];
-
 
1949
	    nv++;
-
 
1950
	}
-
 
1951
 
-
 
1952
	u[0] = x[i]; u[1] = y[j + 1];
-
 
1953
	u[2] = z[i + (j + 1) * nx]; u[3] = 1;
-
 
1954
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
-
 
1955
	    TransVector(u, VT, v);
-
 
1956
	    xx[nv] = v[0] / v[3];
-
 
1957
	    yy[nv] = v[1] / v[3];
-
 
1958
	    nv++;
-
 
1959
	}
-
 
1960
 
-
 
1961
	if (nv > 2) {
-
 
1962
	    newcol = col[icol];
-
 
1963
	    if (DoLighting) {
-
 
1964
		r = (int)(shade * R_RED(newcol));
-
 
1965
		g = (int)(shade * R_GREEN(newcol));
-
 
1966
		b = (int)(shade * R_BLUE(newcol));
-
 
1967
		newcol = R_RGB(r, g, b);
-
 
1968
	    }
-
 
1969
	    GPolygon(nv, xx, yy, USER, newcol, border, dd);
-
 
1970
	}
-
 
1971
    }
-
 
1972
}
-
 
1973
 
-
 
1974
 
-
 
1975
static void PerspWindow(double *xlim, double *ylim, double *zlim, pGEDevDesc dd)
-
 
1976
{
-
 
1977
    double pin1, pin2, scale, xdelta, ydelta, xscale, yscale, xadd, yadd;
-
 
1978
    double xmax, xmin, ymax, ymin, xx, yy;
-
 
1979
    Vector3d u, v;
-
 
1980
    int i, j, k;
-
 
1981
 
-
 
1982
    xmax = xmin = ymax = ymin = 0;
-
 
1983
    u[3] = 1;
-
 
1984
    for (i = 0; i < 2; i++) {
-
 
1985
	u[0] = xlim[i];
-
 
1986
	for (j = 0; j < 2; j++) {
-
 
1987
	    u[1] = ylim[j];
-
 
1988
	    for (k = 0; k < 2; k++) {
-
 
1989
		u[2] = zlim[k];
-
 
1990
		TransVector(u, VT, v);
-
 
1991
		xx = v[0] / v[3];
-
 
1992
		yy = v[1] / v[3];
-
 
1993
		if (xx > xmax) xmax = xx;
-
 
1994
		if (xx < xmin) xmin = xx;
-
 
1995
		if (yy > ymax) ymax = yy;
-
 
1996
		if (yy < ymin) ymin = yy;
-
 
1997
	    }
-
 
1998
	}
-
 
1999
    }
-
 
2000
    pin1 = GConvertXUnits(1.0, NPC, INCHES, dd);
-
 
2001
    pin2 = GConvertYUnits(1.0, NPC, INCHES, dd);
-
 
2002
    xdelta = fabs(xmax - xmin);
-
 
2003
    ydelta = fabs(ymax - ymin);
-
 
2004
    xscale = pin1 / xdelta;
-
 
2005
    yscale = pin2 / ydelta;
-
 
2006
    scale = (xscale < yscale) ? xscale : yscale;
-
 
2007
    xadd = .5 * (pin1 / scale - xdelta);
-
 
2008
    yadd = .5 * (pin2 / scale - ydelta);
-
 
2009
    GScale(xmin - xadd, xmax + xadd, 1, dd);
-
 
2010
    GScale(ymin - yadd, ymax + yadd, 2, dd);
-
 
2011
    GMapWin2Fig(dd);
-
 
2012
}
-
 
2013
 
-
 
2014
static int LimitCheck(double *lim, double *c, double *s)
-
 
2015
{
-
 
2016
    if (!R_FINITE(lim[0]) || !R_FINITE(lim[1]) || lim[0] >= lim[1])
-
 
2017
	return 0;
-
 
2018
    *s = 0.5 * fabs(lim[1] - lim[0]);
-
 
2019
    *c = 0.5 * (lim[1] + lim[0]);
-
 
2020
    return 1;
-
 
2021
}
-
 
2022
 
-
 
2023
/* PerspBox: The following code carries out a visibility test
-
 
2024
   on the surfaces of the xlim/ylim/zlim box around the plot.
-
 
2025
   If front = 0, only the faces with their inside toward the
-
 
2026
   eyepoint are drawn.  If front = 1, only the faces with
-
 
2027
   their outside toward the eye are drawn.  This lets us carry
-
 
2028
   out hidden line removal by drawing any faces which will be
-
 
2029
   obscured before the surface, and those which will not be
-
 
2030
   obscured after the surface. 
-
 
2031
 
-
 
2032
   Unfortunately as PR#202 showed, this is simplistic as the surface
-
 
2033
   can go outside the box.
-
 
2034
*/
-
 
2035
 
-
 
2036
/* The vertices of the box */
-
 
2037
static short int Vertex[8][3] = {
-
 
2038
    {0, 0, 0},
-
 
2039
    {0, 0, 1},
-
 
2040
    {0, 1, 0},
-
 
2041
    {0, 1, 1},
-
 
2042
    {1, 0, 0},
-
 
2043
    {1, 0, 1},
-
 
2044
    {1, 1, 0},
-
 
2045
    {1, 1, 1},
-
 
2046
};
-
 
2047
 
-
 
2048
/* The vertices visited when tracing a face */
-
 
2049
static short int Face[6][4] = {
-
 
2050
    {0, 1, 5, 4},
-
 
2051
    {2, 6, 7, 3},
-
 
2052
    {0, 2, 3, 1},
-
 
2053
    {4, 5, 7, 6},
-
 
2054
    {0, 4, 6, 2},
-
 
2055
    {1, 3, 7, 5},
-
 
2056
};
-
 
2057
 
-
 
2058
/* The edges drawn when tracing a face */
-
 
2059
static short int Edge[6][4] = {
-
 
2060
    { 0, 1, 2, 3},
-
 
2061
    { 4, 5, 6, 7},
-
 
2062
    { 8, 7, 9, 0},
-
 
2063
    { 2,10, 5,11},
-
 
2064
    { 3,11, 4, 8},
-
 
2065
    { 9, 6,10, 1},
-
 
2066
};
-
 
2067
 
-
 
2068
 
-
 
2069
static void PerspBox(int front, double *x, double *y, double *z, 
-
 
2070
		     char *EdgeDone, pGEDevDesc dd)
-
 
2071
{
-
 
2072
    Vector3d u0, v0, u1, v1, u2, v2, u3, v3;
-
 
2073
    double d[3], e[3];
-
 
2074
    int f, i, p0, p1, p2, p3, nearby;
-
 
2075
    int ltysave = gpptr(dd)->lty;
-
 
2076
    
-
 
2077
    gpptr(dd)->lty = front ? LTY_DOTTED : LTY_SOLID;
-
 
2078
 
-
 
2079
    for (f = 0; f < 6; f++) {
-
 
2080
	p0 = Face[f][0];
-
 
2081
	p1 = Face[f][1];
-
 
2082
	p2 = Face[f][2];
-
 
2083
	p3 = Face[f][3];
-
 
2084
 
-
 
2085
	u0[0] = x[Vertex[p0][0]];
-
 
2086
	u0[1] = y[Vertex[p0][1]];
-
 
2087
	u0[2] = z[Vertex[p0][2]];
-
 
2088
	u0[3] = 1;
-
 
2089
	u1[0] = x[Vertex[p1][0]];
-
 
2090
	u1[1] = y[Vertex[p1][1]];
-
 
2091
	u1[2] = z[Vertex[p1][2]];
-
 
2092
	u1[3] = 1;
-
 
2093
	u2[0] = x[Vertex[p2][0]];
-
 
2094
	u2[1] = y[Vertex[p2][1]];
-
 
2095
	u2[2] = z[Vertex[p2][2]];
-
 
2096
	u2[3] = 1;
-
 
2097
	u3[0] = x[Vertex[p3][0]];
-
 
2098
	u3[1] = y[Vertex[p3][1]];
-
 
2099
	u3[2] = z[Vertex[p3][2]];
-
 
2100
	u3[3] = 1;
-
 
2101
 
-
 
2102
	TransVector(u0, VT, v0);
-
 
2103
	TransVector(u1, VT, v1);
-
 
2104
	TransVector(u2, VT, v2);
-
 
2105
	TransVector(u3, VT, v3);
-
 
2106
 
-
 
2107
	/* Visibility test. */
-
 
2108
	/* Determine whether the surface normal is toward the eye. */
-
 
2109
	/* Note that we only draw lines once. */
-
 
2110
 
-
 
2111
	for (i = 0; i < 3; i++) {
-
 
2112
	    d[i] = v1[i]/v1[3] - v0[i]/v0[3];
-
 
2113
	    e[i] = v2[i]/v2[3] - v1[i]/v1[3];
-
 
2114
	}
-
 
2115
	nearby = (d[0]*e[1] - d[1]*e[0]) < 0;
-
 
2116
 
-
 
2117
	if ((front && nearby) || (!front && !nearby)) {
-
 
2118
	    if (!EdgeDone[Edge[f][0]]++)
-
 
2119
		GLine(v0[0]/v0[3], v0[1]/v0[3],
-
 
2120
		      v1[0]/v1[3], v1[1]/v1[3], USER, dd);
-
 
2121
	    if (!EdgeDone[Edge[f][1]]++)
-
 
2122
		GLine(v1[0]/v1[3], v1[1]/v1[3],
-
 
2123
		      v2[0]/v2[3], v2[1]/v2[3], USER, dd);
-
 
2124
	    if (!EdgeDone[Edge[f][2]]++)
-
 
2125
		GLine(v2[0]/v2[3], v2[1]/v2[3],
-
 
2126
		      v3[0]/v3[3], v3[1]/v3[3], USER, dd);
-
 
2127
	    if (!EdgeDone[Edge[f][3]]++)
-
 
2128
		GLine(v3[0]/v3[3], v3[1]/v3[3],
-
 
2129
		      v0[0]/v0[3], v0[1]/v0[3], USER, dd);
-
 
2130
	}
-
 
2131
    }
-
 
2132
    gpptr(dd)->lty = ltysave;
-
 
2133
}
-
 
2134
 
-
 
2135
/* PerspAxes:
-
 
2136
 */
-
 
2137
 
-
 
2138
/* Starting vertex for possible axes */
-
 
2139
static short int AxisStart[8] = { 0, 0, 2, 4, 0, 4, 2, 6 };
-
 
2140
 
-
 
2141
/* Tick vector for possible axes */
-
 
2142
static short int TickVector[8][3] = {
-
 
2143
    {0, -1, -1},
-
 
2144
    {-1, 0, -1},
-
 
2145
    {0, 1, -1},
-
 
2146
    {1, 0, -1},
-
 
2147
    {-1, -1, 0},
-
 
2148
    {1, -1, 0},
-
 
2149
    {-1, 1, 0},
-
 
2150
    {1, 1, 0}};
-
 
2151
 
-
 
2152
static int lowest(double y1, double y2, double y3, double y4) {
-
 
2153
    return ((y1 <= y2) && (y1 <= y3) && (y1 <= y4));
-
 
2154
}
-
 
2155
 
-
 
2156
static double labelAngle(double x1, double y1, double x2, double y2) {
-
 
2157
    double dx, dy;
-
 
2158
    double angle;
-
 
2159
    dx = fabs(x2 - x1);
-
 
2160
    if (x2 > x1)
-
 
2161
	dy = y2 - y1;
-
 
2162
    else
-
 
2163
	dy = y1 - y2;
-
 
2164
    if (dx == 0) {
-
 
2165
	if (dy > 0)
-
 
2166
	    angle = 90;
-
 
2167
	else
-
 
2168
	    angle = 270;
-
 
2169
    } else {
-
 
2170
	angle = (180 / M_PI) * atan2(dy, dx);
-
 
2171
    }
-
 
2172
    return angle;
-
 
2173
}
-
 
2174
 
-
 
2175
static void PerspAxis(double *x, double *y, double *z,
-
 
2176
		      int axis, int axisType, int nTicks, int tickType,
-
 
2177
		      const char *label, cetype_t enc, pGEDevDesc dd)
-
 
2178
{
-
 
2179
    Vector3d u1={0.,0.,0.,0.}, u2={0.,0.,0.,0.}, u3={0.,0.,0.,0.}, v1, v2, v3;
-
 
2180
    double tickLength = .03; /* proportion of axis length */
-
 
2181
    double min, max, d_frac;
-
 
2182
    double *range = NULL; /* -Wall */
-
 
2183
    double axp[3];
-
 
2184
    int nint, i;
-
 
2185
    SEXP at, lab;
-
 
2186
    double cexsave = gpptr(dd)->cex;
-
 
2187
    int fontsave = gpptr(dd)->font;
-
 
2188
 
-
 
2189
 
-
 
2190
    switch (axisType) {
-
 
2191
    case 0:
-
 
2192
	min = x[0];	max = x[1];	range = x;	break;
-
 
2193
    case 1:
-
 
2194
	min = y[0];	max = y[1];	range = y;	break;
-
 
2195
    case 2:
-
 
2196
	min = z[0];	max = z[1];	range = z;	break;
-
 
2197
    }
-
 
2198
    d_frac = 0.1*(max - min);
-
 
2199
    nint = nTicks - 1; if(!nint) nint++;
-
 
2200
    i = nint;
-
 
2201
    GPretty(&min, &max, &nint);
-
 
2202
    /* GPretty() rarely gives values too much outside range ..
-
 
2203
       2D axis() clip these, we play cheaper */
-
 
2204
    while((min < range[0] - d_frac || range[1] + d_frac < max) && i < 20) {
-
 
2205
	nint = ++i;
-
 
2206
	min = range[0];
-
 
2207
	max = range[1];
-
 
2208
	GPretty(&min, &max, &nint);
-
 
2209
    }
-
 
2210
    axp[0] = min;
-
 
2211
    axp[1] = max;
-
 
2212
    axp[2] = nint;
-
 
2213
    /* Do the following calculations for both ticktypes */
-
 
2214
    switch (axisType) {
-
 
2215
    case 0:
-
 
2216
	u1[0] = min;
-
 
2217
	u1[1] = y[Vertex[AxisStart[axis]][1]];
-
 
2218
	u1[2] = z[Vertex[AxisStart[axis]][2]];
-
 
2219
	break;
-
 
2220
    case 1:
-
 
2221
	u1[0] = x[Vertex[AxisStart[axis]][0]];
-
 
2222
	u1[1] = min;
-
 
2223
	u1[2] = z[Vertex[AxisStart[axis]][2]];
-
 
2224
	break;
-
 
2225
    case 2:
-
 
2226
	u1[0] = x[Vertex[AxisStart[axis]][0]];
-
 
2227
	u1[1] = y[Vertex[AxisStart[axis]][1]];
-
 
2228
	u1[2] = min;
-
 
2229
	break;
-
 
2230
    }
-
 
2231
    u1[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
-
 
2232
    u1[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
-
 
2233
    u1[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
-
 
2234
    u1[3] = 1;
-
 
2235
    switch (axisType) {
-
 
2236
    case 0:
-
 
2237
	u2[0] = max;
-
 
2238
	u2[1] = u1[1];
-
 
2239
	u2[2] = u1[2];
-
 
2240
	break;
-
 
2241
    case 1:
-
 
2242
	u2[0] = u1[0];
-
 
2243
	u2[1] = max;
-
 
2244
	u2[2] = u1[2];
-
 
2245
	break;
-
 
2246
    case 2:
-
 
2247
	u2[0] = u1[0];
-
 
2248
	u2[1] = u1[1];
-
 
2249
	u2[2] = max;
-
 
2250
	break;
-
 
2251
    }
-
 
2252
    u2[3] = 1;
-
 
2253
    /* The axis label has to be further out for "detailed" ticks
-
 
2254
       in order to leave room for the tick labels */
-
 
2255
    switch (tickType) {
-
 
2256
    case 1: /* "simple": just an arrow parallel to axis, indicating direction
-
 
2257
	       of increase */
-
 
2258
	u3[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
-
 
2259
	u3[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
-
 
2260
	u3[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
-
 
2261
	break;
-
 
2262
    case 2:
-
 
2263
	u3[0] = u1[0] + 2.5*tickLength*(x[1]-x[0])*TickVector[axis][0];
-
 
2264
	u3[1] = u1[1] + 2.5*tickLength*(y[1]-y[0])*TickVector[axis][1];
-
 
2265
	u3[2] = u1[2] + 2.5*tickLength*(z[1]-z[0])*TickVector[axis][2];
-
 
2266
	break;
-
 
2267
    }
-
 
2268
    switch (axisType) {
-
 
2269
    case 0:
-
 
2270
	u3[0] = (min + max)/2;
-
 
2271
	break;
-
 
2272
    case 1:
-
 
2273
	u3[1] = (min + max)/2;
-
 
2274
	break;
-
 
2275
    case 2:
-
 
2276
	u3[2] = (min + max)/2;
-
 
2277
	break;
-
 
2278
    }
-
 
2279
    u3[3] = 1;
-
 
2280
    TransVector(u1, VT, v1);
-
 
2281
    TransVector(u2, VT, v2);
-
 
2282
    TransVector(u3, VT, v3);
-
 
2283
    /* Draw axis label */
-
 
2284
    /* change in 2.5.0 to use cex.lab and font.lab */
-
 
2285
    gpptr(dd)->cex = gpptr(dd)->cexbase * gpptr(dd)->cexlab;
-
 
2286
    gpptr(dd)->font = gpptr(dd)->fontlab;
-
 
2287
    GText(v3[0]/v3[3], v3[1]/v3[3], USER, label, enc, .5, .5,
-
 
2288
	  labelAngle(v1[0]/v1[3], v1[1]/v1[3], v2[0]/v2[3], v2[1]/v2[3]),
-
 
2289
	  dd);
-
 
2290
    /* Draw axis ticks */
-
 
2291
    /* change in 2.5.0 to use cex.axis and font.axis */
-
 
2292
    gpptr(dd)->cex = gpptr(dd)->cexbase * gpptr(dd)->cexaxis;
-
 
2293
    gpptr(dd)->font = gpptr(dd)->fontaxis;
-
 
2294
    switch (tickType) {
-
 
2295
    case 1: /* "simple": just an arrow parallel to axis, indicating direction
-
 
2296
	       of increase */
-
 
2297
	/* arrow head is 0.25 inches long, with angle 30 degrees,
-
 
2298
	   and drawn at v2 end of line */
-
 
2299
	GArrow(v1[0]/v1[3], v1[1]/v1[3],
-
 
2300
	       v2[0]/v2[3], v2[1]/v2[3], USER,
-
 
2301
	       0.1, 10, 2, dd);
-
 
2302
	break;
-
 
2303
    case 2: /* "detailed": normal ticks as per 2D plots */
-
 
2304
	PROTECT(at = CreateAtVector(axp, range, 7, FALSE));
-
 
2305
	PROTECT(lab = labelformat(at));
-
 
2306
	for (i=0; i<length(at); i++) {
-
 
2307
	    switch (axisType) {
-
 
2308
	    case 0:
-
 
2309
		u1[0] = REAL(at)[i];
-
 
2310
		u1[1] = y[Vertex[AxisStart[axis]][1]];
-
 
2311
		u1[2] = z[Vertex[AxisStart[axis]][2]];
-
 
2312
		break;
-
 
2313
	    case 1:
-
 
2314
		u1[0] = x[Vertex[AxisStart[axis]][0]];
-
 
2315
		u1[1] = REAL(at)[i];
-
 
2316
		u1[2] = z[Vertex[AxisStart[axis]][2]];
-
 
2317
		break;
-
 
2318
	    case 2:
-
 
2319
		u1[0] = x[Vertex[AxisStart[axis]][0]];
-
 
2320
		u1[1] = y[Vertex[AxisStart[axis]][1]];
-
 
2321
		u1[2] = REAL(at)[i];
-
 
2322
		break;
-
 
2323
	    }
-
 
2324
	    u1[3] = 1;
-
 
2325
	    u2[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
-
 
2326
	    u2[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
-
 
2327
	    u2[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
-
 
2328
	    u2[3] = 1;
-
 
2329
	    u3[0] = u2[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
-
 
2330
	    u3[1] = u2[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
-
 
2331
	    u3[2] = u2[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
-
 
2332
	    u3[3] = 1;
-
 
2333
	    TransVector(u1, VT, v1);
-
 
2334
	    TransVector(u2, VT, v2);
-
 
2335
	    TransVector(u3, VT, v3);
-
 
2336
	    /* Draw tick line */
-
 
2337
	    GLine(v1[0]/v1[3], v1[1]/v1[3],
-
 
2338
		  v2[0]/v2[3], v2[1]/v2[3], USER, dd);
-
 
2339
	    /* Draw tick label */
-
 
2340
	    GText(v3[0]/v3[3], v3[1]/v3[3], USER,
-
 
2341
		  CHAR(STRING_ELT(lab, i)),
-
 
2342
		  getCharCE(STRING_ELT(lab, i)),
-
 
2343
		  .5, .5, 0, dd);
-
 
2344
	}
-
 
2345
	UNPROTECT(2);
-
 
2346
	break;
-
 
2347
    }
-
 
2348
    gpptr(dd)->cex = cexsave;
-
 
2349
    gpptr(dd)->font = fontsave;
-
 
2350
}
-
 
2351
 
-
 
2352
/* Determine the transformed (x, y) coordinates (in USER space)
-
 
2353
 * for the four corners of the x-y plane of the persp plot
-
 
2354
 * These will be used to determine which sides of the persp
-
 
2355
 * plot to label with axes
-
 
2356
 * The strategy is to determine which corner has the lowest y-value
-
 
2357
 * to decide which of the x- and y-axes to label AND which corner
-
 
2358
 * has the lowest x-value to decide which of the z-axes to label
-
 
2359
 */
-
 
2360
static void PerspAxes(double *x, double *y, double *z,
-
 
2361
		      const char *xlab, cetype_t xenc,
-
 
2362
		      const char *ylab, cetype_t yenc,
-
 
2363
		      const char *zlab, cetype_t zenc,
-
 
2364
		      int nTicks, int tickType, pGEDevDesc dd)
-
 
2365
{
-
 
2366
    int xAxis=0, yAxis=0, zAxis=0; /* -Wall */
-
 
2367
    int xpdsave;
-
 
2368
    Vector3d u0, u1, u2, u3;
-
 
2369
    Vector3d v0, v1, v2, v3;
-
 
2370
    u0[0] = x[0];
-
 
2371
    u0[1] = y[0];
-
 
2372
    u0[2] = z[0];
-
 
2373
    u0[3] = 1;
-
 
2374
    u1[0] = x[1];
-
 
2375
    u1[1] = y[0];
-
 
2376
    u1[2] = z[0];
-
 
2377
    u1[3] = 1;
-
 
2378
    u2[0] = x[0];
-
 
2379
    u2[1] = y[1];
-
 
2380
    u2[2] = z[0];
-
 
2381
    u2[3] = 1;
-
 
2382
    u3[0] = x[1];
-
 
2383
    u3[1] = y[1];
-
 
2384
    u3[2] = z[0];
-
 
2385
    u3[3] = 1;
-
 
2386
    TransVector(u0, VT, v0);
-
 
2387
    TransVector(u1, VT, v1);
-
 
2388
    TransVector(u2, VT, v2);
-
 
2389
    TransVector(u3, VT, v3);
-
 
2390
 
-
 
2391
    /* to fit in the axis labels */
-
 
2392
    xpdsave = gpptr(dd)->xpd;
-
 
2393
    gpptr(dd)->xpd = 1;
-
 
2394
 
-
 
2395
    /* Figure out which X and Y axis to draw */
-
 
2396
    if (lowest(v0[1]/v0[3], v1[1]/v1[3], v2[1]/v2[3], v3[1]/v3[3])) {
-
 
2397
	xAxis = 0;
-
 
2398
	yAxis = 1;
-
 
2399
    } else if (lowest(v1[1]/v1[3], v0[1]/v0[3], v2[1]/v2[3], v3[1]/v3[3])) {
-
 
2400
	xAxis = 0;
-
 
2401
	yAxis = 3;
-
 
2402
    } else if (lowest(v2[1]/v2[3], v1[1]/v1[3], v0[1]/v0[3], v3[1]/v3[3])) {
-
 
2403
	xAxis = 2;
-
 
2404
	yAxis = 1;
-
 
2405
    } else if (lowest(v3[1]/v3[3], v1[1]/v1[3], v2[1]/v2[3], v0[1]/v0[3])) {
-
 
2406
	xAxis = 2;
-
 
2407
	yAxis = 3;
-
 
2408
    } else
-
 
2409
	warning(_("Axis orientation not calculated"));
-
 
2410
    PerspAxis(x, y, z, xAxis, 0, nTicks, tickType, xlab, xenc, dd);
-
 
2411
    PerspAxis(x, y, z, yAxis, 1, nTicks, tickType, ylab, yenc, dd);
-
 
2412
    /* Figure out which Z axis to draw */
-
 
2413
    if (lowest(v0[0]/v0[3], v1[0]/v1[3], v2[0]/v2[3], v3[0]/v3[3])) {
-
 
2414
	zAxis = 4;
-
 
2415
    } else if (lowest(v1[0]/v1[3], v0[0]/v0[3], v2[0]/v2[3], v3[0]/v3[3])) {
-
 
2416
	zAxis = 5;
-
 
2417
    } else if (lowest(v2[0]/v2[3], v1[0]/v1[3], v0[0]/v0[3], v3[0]/v3[3])) {
-
 
2418
	zAxis = 6;
-
 
2419
    } else if (lowest(v3[0]/v3[3], v1[0]/v1[3], v2[0]/v2[3], v0[0]/v0[3])) {
-
 
2420
	zAxis = 7;
-
 
2421
    } else
-
 
2422
	warning(_("Axis orientation not calculated"));
-
 
2423
    PerspAxis(x, y, z, zAxis, 2, nTicks, tickType, zlab, zenc, dd);
-
 
2424
 
-
 
2425
    gpptr(dd)->xpd = xpdsave;
-
 
2426
}
-
 
2427
 
-
 
2428
SEXP attribute_hidden do_persp(SEXP call, SEXP op, SEXP args, SEXP env)
-
 
2429
{
-
 
2430
    SEXP x, y, z, xlim, ylim, zlim;
-
 
2431
    SEXP depth, indx, originalArgs;
-
 
2432
    SEXP col, border, xlab, ylab, zlab;
-
 
2433
    double theta, phi, r, d;
-
 
2434
    double ltheta, lphi;
-
 
2435
    double expand, xc = 0.0, yc = 0.0, zc = 0.0, xs = 0.0, ys = 0.0, zs = 0.0;
-
 
2436
    int i, j, scale, ncol, dobox, doaxes, nTicks, tickType;
-
 
2437
    char EdgeDone[12]; /* Which edges have been drawn previously */
-
 
2438
    pGEDevDesc dd;
-
 
2439
 
-
 
2440
    if (length(args) < 24)  /* 24 plus any inline par()s */
-
 
2441
	error(_("too few parameters"));
-
 
2442
    gcall = call;
-
 
2443
    originalArgs = args;
-
 
2444
 
-
 
2445
    PROTECT(x = coerceVector(CAR(args), REALSXP));
-
 
2446
    if (length(x) < 2) error(_("invalid '%s' argument"), "x");
-
 
2447
    args = CDR(args);
-
 
2448
 
-
 
2449
    PROTECT(y = coerceVector(CAR(args), REALSXP));
-
 
2450
    if (length(y) < 2) error(_("invalid '%s' argument"), "y");
-
 
2451
    args = CDR(args);
-
 
2452
 
-
 
2453
    PROTECT(z = coerceVector(CAR(args), REALSXP));
-
 
2454
    if (!isMatrix(z) || nrows(z) != length(x) || ncols(z) != length(y))
-
 
2455
	error(_("invalid '%s' argument"), "z");
-
 
2456
    args = CDR(args);
-
 
2457
 
-
 
2458
    PROTECT(xlim = coerceVector(CAR(args), REALSXP));
-
 
2459
    if (length(xlim) != 2) error(_("invalid '%s' argument"), "xlim");
-
 
2460
    args = CDR(args);
-
 
2461
 
-
 
2462
    PROTECT(ylim = coerceVector(CAR(args), REALSXP));
-
 
2463
    if (length(ylim) != 2) error(_("invalid '%s' argument"), "ylim");
-
 
2464
    args = CDR(args);
-
 
2465
 
-
 
2466
    PROTECT(zlim = coerceVector(CAR(args), REALSXP));
-
 
2467
    if (length(zlim) != 2) error(_("invalid '%s' argument"), "zlim");
-
 
2468
    args = CDR(args);
-
 
2469
 
-
 
2470
    /* Checks on x/y/z Limits */
-
 
2471
 
-
 
2472
    if (!LimitCheck(REAL(xlim), &xc, &xs))
-
 
2473
	error(_("invalid 'x' limits"));
-
 
2474
    if (!LimitCheck(REAL(ylim), &yc, &ys))
-
 
2475
	error(_("invalid 'y' limits"));
-
 
2476
    if (!LimitCheck(REAL(zlim), &zc, &zs))
-
 
2477
	error(_("invalid 'z' limits"));
-
 
2478
 
-
 
2479
    theta = asReal(CAR(args));	args = CDR(args);
-
 
2480
    phi	  = asReal(CAR(args));	args = CDR(args);
-
 
2481
    r	= asReal(CAR(args));	args = CDR(args);
-
 
2482
    d	= asReal(CAR(args));	args = CDR(args);
-
 
2483
    scale  = asLogical(CAR(args)); args = CDR(args);
-
 
2484
    expand = asReal(CAR(args)); args = CDR(args);
-
 
2485
    col	   = CAR(args);		args = CDR(args);
-
 
2486
    border = CAR(args);		args = CDR(args);
-
 
2487
    ltheta = asReal(CAR(args)); args = CDR(args);
-
 
2488
    lphi   = asReal(CAR(args)); args = CDR(args);
-
 
2489
    Shade  = asReal(CAR(args)); args = CDR(args);
-
 
2490
    dobox  = asLogical(CAR(args)); args = CDR(args);
-
 
2491
    doaxes = asLogical(CAR(args)); args = CDR(args);
-
 
2492
    nTicks = asInteger(CAR(args)); args = CDR(args);
-
 
2493
    tickType = asInteger(CAR(args)); args = CDR(args);
-
 
2494
    xlab = CAR(args); args = CDR(args);
-
 
2495
    ylab = CAR(args); args = CDR(args);
-
 
2496
    zlab = CAR(args); args = CDR(args);
-
 
2497
    if (!isString(xlab) || length(xlab) < 1)
-
 
2498
	error(_("'xlab' must be a character vector of length 1"));
-
 
2499
    if (!isString(ylab) || length(ylab) < 1)
-
 
2500
	error(_("'ylab' must be a character vector of length 1"));
-
 
2501
    if (!isString(zlab) || length(zlab) < 1)
-
 
2502
	error(_("'zlab' must be a character vector of length 1"));
-
 
2503
 
-
 
2504
    if (R_FINITE(Shade) && Shade <= 0) Shade = 1;
-
 
2505
    if (R_FINITE(ltheta) && R_FINITE(lphi) && R_FINITE(Shade))
-
 
2506
	DoLighting = TRUE;
-
 
2507
    else
-
 
2508
	DoLighting = FALSE;
-
 
2509
 
-
 
2510
    if (!scale) {
-
 
2511
	double s;
-
 
2512
	s = xs;
-
 
2513
	if (s < ys) s = ys;
-
 
2514
	if (s < zs) s = zs;
-
 
2515
	xs = s; ys = s; zs = s;
-
 
2516
    }
-
 
2517
 
-
 
2518
    /* Parameter Checks */
-
 
2519
 
-
 
2520
    if (!R_FINITE(theta) || !R_FINITE(phi) || !R_FINITE(r) || !R_FINITE(d) ||
-
 
2521
	d < 0 || r < 0)
-
 
2522
	error(_("invalid viewing parameters"));
-
 
2523
    if (!R_FINITE(expand) || expand < 0)
-
 
2524
	error(_("invalid '%s' value"), "expand");
-
 
2525
    if (scale == NA_LOGICAL)
-
 
2526
	scale = 0;
-
 
2527
    if ((nTicks == NA_INTEGER) || (nTicks < 0))
-
 
2528
	error(_("invalid '%s' value"), "nticks");
-
 
2529
    if ((tickType == NA_INTEGER) || (tickType < 1) || (tickType > 2))
-
 
2530
	error(_("invalid '%s' value"), "ticktype");
-
 
2531
 
-
 
2532
    dd = GEcurrentDevice();
-
 
2533
 
-
 
2534
    GNewPlot(GRecording(call, dd));
-
 
2535
 
-
 
2536
    PROTECT(col = FixupCol(col, gpptr(dd)->bg));
-
 
2537
    ncol = LENGTH(col);
-
 
2538
    if (ncol < 1) error(_("invalid '%s' specification"), "col");
-
 
2539
    if(!R_OPAQUE(INTEGER(col)[0])) DoLighting = FALSE;
-
 
2540
    PROTECT(border = FixupCol(border, gpptr(dd)->fg));
-
 
2541
    if (length(border) < 1)
-
 
2542
	error(_("invalid '%s' specification"), "border");
-
 
2543
 
-
 
2544
    GSetState(1, dd);
-
 
2545
    GSavePars(dd);
-
 
2546
    ProcessInlinePars(args, dd, call);
-
 
2547
    if (length(border) > 1)
-
 
2548
	gpptr(dd)->fg = INTEGER(border)[0];
-
 
2549
    gpptr(dd)->xlog = gpptr(dd)->ylog = FALSE;
-
 
2550
 
-
 
2551
    /* Set up the light vector (if any) */
-
 
2552
    if (DoLighting)
-
 
2553
	SetUpLight(ltheta, lphi);
-
 
2554
 
-
 
2555
    /* Mark box edges as undrawn */
-
 
2556
    for (i = 0; i< 12; i++)
-
 
2557
	EdgeDone[i] = 0;
-
 
2558
 
-
 
2559
    /* Specify the viewing transformation. */
-
 
2560
 
-
 
2561
    SetToIdentity(VT);             /* Initialization */
-
 
2562
    Translate(-xc, -yc, -zc);      /* center at the origin */
-
 
2563
    Scale(1/xs, 1/ys, expand/zs);  /* scale extents to [-1,1] */
-
 
2564
    XRotate(-90.0);                /* rotate x-y plane to horizontal */
-
 
2565
    YRotate(-theta);               /* azimuthal rotation */
-
 
2566
    XRotate(phi);                  /* elevation rotation */
-
 
2567
    Translate(0.0, 0.0, -r - d);   /* translate the eyepoint to the origin */
-
 
2568
    Perspective(d);                /* perspective */
-
 
2569
 
-
 
2570
    /* Specify the plotting window. */
-
 
2571
    /* Here we map the vertices of the cube */
-
 
2572
    /* [xmin,xmax]*[ymin,ymax]*[zmin,zmax] */
-
 
2573
    /* to the screen and then chose a window */
-
 
2574
    /* which is symmetric about (0,0). */
-
 
2575
 
-
 
2576
    PerspWindow(REAL(xlim), REAL(ylim), REAL(zlim), dd);
-
 
2577
 
-
 
2578
    /* Compute facet order:
-
 
2579
       We order the facets by depth and then draw them back to front.
-
 
2580
       This is the "painters" algorithm. */
-
 
2581
 
-
 
2582
    PROTECT(depth = allocVector(REALSXP, (nrows(z) - 1)*(ncols(z) - 1)));
-
 
2583
    PROTECT(indx = allocVector(INTSXP, (nrows(z) - 1)*(ncols(z) - 1)));
-
 
2584
    DepthOrder(REAL(z), REAL(x), REAL(y), nrows(z), ncols(z),
-
 
2585
	       REAL(depth), INTEGER(indx));
-
 
2586
 
-
 
2587
    GMode(1, dd);
-
 
2588
 
-
 
2589
    if (dobox) {
-
 
2590
	/* Draw (solid) faces which face away from the viewer */
-
 
2591
	PerspBox(0, REAL(xlim), REAL(ylim), REAL(zlim), EdgeDone, dd);
-
 
2592
	if (doaxes) {
-
 
2593
	    SEXP xl = STRING_ELT(xlab, 0), yl = STRING_ELT(ylab, 0),
-
 
2594
		zl = STRING_ELT(zlab, 0);
-
 
2595
	    PerspAxes(REAL(xlim), REAL(ylim), REAL(zlim),
-
 
2596
		      (xl == NA_STRING) ? "" : CHAR(xl), getCharCE(xl),
-
 
2597
		      (yl == NA_STRING) ? "" : CHAR(yl), getCharCE(yl),
-
 
2598
		      (zl == NA_STRING) ? "" : CHAR(zl), getCharCE(zl),
-
 
2599
		      nTicks, tickType, dd);
-
 
2600
	}
-
 
2601
    }
-
 
2602
 
-
 
2603
    DrawFacets(REAL(z), REAL(x), REAL(y), nrows(z), ncols(z), INTEGER(indx),
-
 
2604
	       1/xs, 1/ys, expand/zs,
-
 
2605
	       INTEGER(col), ncol, INTEGER(border)[0]);
-
 
2606
 
-
 
2607
    /* Draw (dotted) not-already-plotted edges of faces which face
-
 
2608
       towards from the viewer */
-
 
2609
    if (dobox)
-
 
2610
	PerspBox(1, REAL(xlim), REAL(ylim), REAL(zlim), EdgeDone, dd);
-
 
2611
    GMode(0, dd);
-
 
2612
 
-
 
2613
    GRestorePars(dd);
-
 
2614
    UNPROTECT(10);
-
 
2615
    if (GRecording(call, dd))
-
 
2616
	GErecordGraphicOperation(op, originalArgs, dd);
-
 
2617
 
-
 
2618
    PROTECT(x = allocVector(REALSXP, 16));
-
 
2619
    PROTECT(y = allocVector(INTSXP, 2));
-
 
2620
    for (i = 0; i < 4; i++)
-
 
2621
	for (j = 0; j < 4; j++)
-
 
2622
	    REAL(x)[i + j * 4] = VT[i][j];
-
 
2623
    INTEGER(y)[0] = 4;
-
 
2624
    INTEGER(y)[1] = 4;
-
 
2625
    setAttrib(x, R_DimSymbol, y);
-
 
2626
    UNPROTECT(2);
-
 
2627
    return x;
-
 
2628
}
-