Revision 3000e7e52a06e6e2e812a26883e6a5e7eab81fbf authored by Deepayan Sarkar on 06 October 2003, 00:00:00 UTC, committed by Gabor Csardi on 06 October 2003, 00:00:00 UTC
1 parent 6ed2bb4
Raw File
threeDplot.c
#include <R.h>
#include <Rinternals.h>





static double calculateCosOfAngleOfReflection(double *x, double *y, double *z,
					      double *ls) 
{
    /* Bad name, change later. The idea is, given the quadrilateral
     * defined by x, y, z, find the cosine of half the angle between a
     * point in the z-axis at infinite distance and the ray reflected
     * by the plane defined by the first three points, where the ray
     * comes from an infinitely distant source in the direction of
     * ls. This means that the result would be the same for any
     * section in a given plane. Could use improvement */

     double x1, x2, y1, y2, z1, z2, cos1, cos2, ans, xm, ym, zm;

     xm = (x[0] + x[1] + x[2] + x[3])/4;
     ym = (y[0] + y[1] + y[2] + y[3])/4;
     zm = (z[0] + z[1] + z[2] + z[3])/4;

     ans = 0;

     /* Theory : We now want the normal to the plane defined by 2 of
      * these points and the average of all four, passing through the
      * average. This has direction (y1 z2 - y2 z1, z1 x2 - z2 x1, x1
      * y2 - x2 y1). We use this to calculate cos of the final angle.
      * Don't feel like writing all the details, but hint : cos1 = cos
      * of angle between z axis and light source, cos2 = angle between
      * z-axis and normal at origin. After all 4 successive pairs,
      * combine these 4 */


     x1 = x[0] - xm;
     y1 = y[0] - ym;
     z1 = z[0] - zm;

     x2 = x[1] - xm;
     y2 = y[1] - ym;
     z2 = z[1] - zm;

     cos1 = ls[2]; /* 0.ls[0] + 0.ls[1] + 1.ls[2] */
     cos2 = x1 * y2 - x2 * y1;
     /* Needs to be normalised */
     cos2 /= sqrt((x1 * y2 - x2 * y1) * (x1 * y2 - x2 * y1) +
		  (y1 * z2 - y2 * z1) * (y1 * z2 - y2 * z1) +
		  (z1 * x2 - z2 * x1) * (z1 * x2 - z2 * x1)); 

     ans += cos2 * cos2 * ((1 + cos1)/2) + 
	     (1 - cos2 * cos2) * ((1 - cos1)/2) + 
	     cos2 * sqrt((1 - cos2 * cos2) * (1 - cos1 * cos1));


     x1 = x[1] - xm;
     y1 = y[1] - ym;
     z1 = z[1] - zm;

     x2 = x[2] - xm;
     y2 = y[2] - ym;
     z2 = z[2] - zm;

     cos1 = ls[2]; /* 0.ls[0] + 0.ls[1] + 1.ls[2] */
     cos2 = x1 * y2 - x2 * y1;
     /* Needs to be normalised */
     cos2 /= sqrt((x1 * y2 - x2 * y1) * (x1 * y2 - x2 * y1) +
		  (y1 * z2 - y2 * z1) * (y1 * z2 - y2 * z1) +
		  (z1 * x2 - z2 * x1) * (z1 * x2 - z2 * x1)); 

     ans += cos2 * cos2 * ((1 + cos1)/2) + 
	     (1 - cos2 * cos2) * ((1 - cos1)/2) + 
	     cos2 * sqrt((1 - cos2 * cos2) * (1 - cos1 * cos1));


     x1 = x[2] - xm;
     y1 = y[2] - ym;
     z1 = z[2] - zm;

     x2 = x[3] - xm;
     y2 = y[3] - ym;
     z2 = z[3] - zm;

     cos1 = ls[2]; /* 0.ls[0] + 0.ls[1] + 1.ls[2] */
     cos2 = x1 * y2 - x2 * y1;
     /* Needs to be normalised */
     cos2 /= sqrt((x1 * y2 - x2 * y1) * (x1 * y2 - x2 * y1) +
		  (y1 * z2 - y2 * z1) * (y1 * z2 - y2 * z1) +
		  (z1 * x2 - z2 * x1) * (z1 * x2 - z2 * x1)); 

     ans += cos2 * cos2 * ((1 + cos1)/2) + 
	     (1 - cos2 * cos2) * ((1 - cos1)/2) + 
	     cos2 * sqrt((1 - cos2 * cos2) * (1 - cos1 * cos1));



     x1 = x[3] - xm;
     y1 = y[3] - ym;
     z1 = z[3] - zm;

     x2 = x[0] - xm;
     y2 = y[0] - ym;
     z2 = z[0] - zm;

     cos1 = ls[2]; /* 0.ls[0] + 0.ls[1] + 1.ls[2] */
     cos2 = x1 * y2 - x2 * y1;
     /* Needs to be normalised */
     cos2 /= sqrt((x1 * y2 - x2 * y1) * (x1 * y2 - x2 * y1) +
		  (y1 * z2 - y2 * z1) * (y1 * z2 - y2 * z1) +
		  (z1 * x2 - z2 * x1) * (z1 * x2 - z2 * x1)); 

     ans += cos2 * cos2 * ((1 + cos1)/2) + 
	     (1 - cos2 * cos2) * ((1 - cos1)/2) + 
	     cos2 * sqrt((1 - cos2 * cos2) * (1 - cos1 * cos1));

     return ans/4;
}






void wireframePanelCalculations(SEXP xArg, SEXP yArg, SEXP zArg, SEXP rotArg, 
				SEXP zaArg, SEXP zbArg, 
				SEXP nxArg, SEXP nyArg, SEXP ngArg,
				SEXP lsArg,
				SEXP env)
{
     /* Arguments supplied */
     double *x;     /* increasing vector of unique x values                      */
     double *y;     /* increasing vector of unique y values                      */
     double *z;     /* long vector of z values, length = nx * ny * ng            */
     double *rot;   /* rotation matrix 4x4 (homogeneous coordinates, as vector)  */
     double za, zb; /* for perspective calculations                              */
     int nx, ny, ng;/* length of x, y and number of groups (conceptually ncol(z))*/  
     double *ls;    /* light source coordinates (norm 1)                         */

     /* Other variables */
     SEXP call, sHeights, sxx, syy, szz, smisc;
     double *heights, *xx, *yy, *zz, *misc;
     int *horder;
     int nh, i;

     x = REAL(xArg);
     y = REAL(yArg);
     z = REAL(zArg);
     rot = REAL(rotArg);

     za = asReal(zaArg);
     zb = asReal(zbArg);
     
     ls = REAL(lsArg);
     
     nx = asInteger(nxArg);
     ny = asInteger(nyArg);
     ng = asInteger(ngArg);

     /* heights corresponds to all the rectangles in the grid. The
      * indexing is conceptually according to the lower left corner of
      * the rectangle. Thus, the length of heights is
      * (nx-1)*(ny-1)*ng. Given i, would later need to figure out
      * which rectangle this corresponds to  */

     nh = (nx-1) * (ny-1) * ng;
     sHeights = PROTECT(allocVector(REALSXP, nh));
     heights = REAL(sHeights);
     
     /* printf("\nStarting height calculation..."); */

     /* Height Calculation: we need to determine the order in which
      * the quadrilaterals are to be drawn. However, It is not clear
      * what would be a good criteria to do this. 
     */
     for (i = 0; i < nh; i++) {
         double tx, ty, tz, th;
	 int txi, tyi, tgi, ti;

	 tgi = i / ((nx-1)*(ny-1)); /* group index             */
	 ti =  i % ((nx-1)*(ny-1)); /* height index w/in group */
	 tyi = ti % (ny-1);         /* y index                 */
	 txi = ti / (ny-1);         /* x index                 */


	 /* (0,0)  corner */
	 tx = x[txi];
	 ty = y[tyi];
	 tz = z[tgi * nx * ny + txi * ny + tyi];
	 heights[i] = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) 
		 / (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);


	 /* (1,0) corner */
	 tx = x[txi + 1];
	 /* ty = y[tyi]; */
	 tz = z[tgi * nx * ny + (txi + 1) * ny + tyi];
	 th = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) 
		 / (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);
	 
	 /*WAS: if (th > heights[i]) heights[i] = th;  similar below*/
	 if (th < heights[i]) heights[i] = th;


	 /* (1,1) corner */
	 /* tx = x[txi + 1]; */
	 ty = y[tyi + 1];
	 tz = z[tgi * nx * ny + (txi + 1) * ny + tyi + 1];
	 th = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) 
		 / (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);
	 if (th < heights[i]) heights[i] = th;


	 /* (0,1) corner */
	 tx = x[txi];
	 /* ty = y[tyi + 1]; */
	 tz = z[tgi * nx * ny + txi * ny + tyi + 1];
	 th = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) 
		 / (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);
	 if (th < heights[i]) heights[i] = th;
     }

     /* printf("\nFinished height calculation, ordering..."); */
     
     call = PROTECT(lang2(install("order"), sHeights));
     sHeights = eval(call, R_GlobalEnv);
     UNPROTECT(2);
     horder = INTEGER(PROTECT(sHeights));

     /* printf("\nFinished ordering, proceeding..."); */


     sxx = PROTECT(allocVector(REALSXP, 4));
     syy = PROTECT(allocVector(REALSXP, 4));
     szz = PROTECT(allocVector(REALSXP, 4));
     smisc = PROTECT(allocVector(REALSXP, 3));
     xx = REAL(sxx);
     yy = REAL(syy);
     zz = REAL(szz);

     misc = REAL(smisc); 
     /* 0: cos angle with normal 
	1: original z-height averaged
	2: group indicator
     */

     /*
     for (i = 0; i < 16; i++) 
	     printf("\nrot.mat: %f", rot[i]);

     printf("\na : %f   zb : %f", za, zb);

     printf("\n nx = %d, ny = %d", nx, ny);
     printf("\nGroup\tx\ty\n");
     */


     call = PROTECT(lang4(install("wirePolygon"), sxx, syy, smisc));

     for (i = 0; i < nh; i++) {
         double tx, ty, tz, txx, tyy, tzz, tmp;
	 int txi, tyi, tgi, ti;

	 ti = horder[i] - 1;

	 tgi = ti / ((nx-1)*(ny-1)); /* group index             */
	 ti =  ti % ((nx-1)*(ny-1)); /* height index w/in group */
	 tyi = ti % (ny-1);          /* y index                 */
	 txi = ti / (ny-1);          /* x index                 */


	 /*
	 printf("\n%d\t%d\t%d\t(%d,%d,%d,%d)", tgi, txi, tyi,
		tgi * nx * ny + txi * ny + tyi,
		tgi * nx * ny + (txi + 1) * ny + tyi,
		tgi * nx * ny + (txi + 1) * ny + tyi + 1,
		tgi * nx * ny + txi * ny + tyi + 1);
	 */

	 misc[2] = (double) tgi + 1;
	 misc[1] = 0;

	 /* (0,0) corner */
	 tx = x[txi];
	 ty = y[tyi];
	 tz = z[tgi * nx * ny + txi * ny + tyi];

	 misc[1] += tz;
	 tmp = (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);

	 txx = (rot[0] * tx + rot[4] * ty + rot[8] * tz + rot[12]) / tmp;
	 tyy = (rot[1] * tx + rot[5] * ty + rot[9] * tz + rot[13]) / tmp;
	 tzz = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) / tmp;

	 txx *= (za + zb * tzz);
	 tyy *= (za + zb * tzz);


	 /*printf("\n%f\t%f\t%f\t%f\t%f\t%f", tx, ty, tz, txx, tyy, tzz);*/


	 xx[0] = txx;
	 yy[0] = tyy;
	 zz[0] = tzz;

	 /* (1,0) corner */
	 tx = x[txi + 1];
	 ty = y[tyi];
	 tz = z[tgi * nx * ny + (txi + 1) * ny + tyi];

	 misc[1] += tz;
	 tmp = (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);

	 txx = (rot[0] * tx + rot[4] * ty + rot[8] * tz + rot[12]) / tmp;
	 tyy = (rot[1] * tx + rot[5] * ty + rot[9] * tz + rot[13]) / tmp;
	 tzz = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) / tmp;

	 txx *= (za + zb * tzz);
	 tyy *= (za + zb * tzz);

	 xx[1] = txx;
	 yy[1] = tyy;
	 zz[1] = tzz;




	 /* (1,1) corner */
	 tx = x[txi + 1];
	 ty = y[tyi + 1];
	 tz = z[tgi * nx * ny + (txi + 1) * ny + tyi + 1];

	 misc[1] += tz;
	 tmp = (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);

	 txx = (rot[0] * tx + rot[4] * ty + rot[8] * tz + rot[12]) / tmp;
	 tyy = (rot[1] * tx + rot[5] * ty + rot[9] * tz + rot[13]) / tmp;
	 tzz = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) / tmp;

	 txx *= (za + zb * tzz);
	 tyy *= (za + zb * tzz);

	 xx[2] = txx;
	 yy[2] = tyy;
	 zz[2] = tzz;




	 /* (0,1) corner */
	 tx = x[txi];
	 ty = y[tyi + 1];
	 tz = z[tgi * nx * ny + txi * ny + tyi + 1];

	 misc[1] += tz;
	 tmp = (rot[3] * tx + rot[7] * ty + rot[11] * tz + rot[15]);

	 txx = (rot[0] * tx + rot[4] * ty + rot[8] * tz + rot[12]) / tmp;
	 tyy = (rot[1] * tx + rot[5] * ty + rot[9] * tz + rot[13]) / tmp;
	 tzz = (rot[2] * tx + rot[6] * ty + rot[10] * tz + rot[14]) / tmp;

	 txx *= (za + zb * tzz);
	 tyy *= (za + zb * tzz);

	 xx[3] = txx;
	 yy[3] = tyy;
	 zz[3] = tzz;



	 /* Done with all four corners */

	 misc[1]/=4;
	 misc[0] = calculateCosOfAngleOfReflection(xx, yy, zz, ls);

	 eval(call, env);



     }

     UNPROTECT(6);
     return;
}




back to top