/*
 * MollweideImageProjection.java  1.0  98/06/03  Carl Burke
 *
 * Provides a mollweide projection of data on a sphere.
 *
 * Copyright (c) 1998 Carl Burke.
 *
 * Derived from code in planet.c Copyright 1998 Torben AE. Mogensen
 */

public class MollweideImageProjection extends ImageProjection
{
    static private final double[] moll_table =
	{0.0, 0.0685055811, 0.1368109534, 0.2047150027,
	 0.2720147303, 0.3385041213, 0.4039727534,
	 0.4682040106, 0.5309726991, 0.5920417499,
	 0.6511575166, 0.7080428038, 0.7623860881,
	 0.8138239166, 0.8619100185, 0.9060553621,
	 0.9453925506, 0.9783738403, 1.0};

    public MollweideImageProjection(int w, int h, SolidNoiseGenerator sng)
    {
	super(w, h, sng);
    }
    public void renderTerrain()
    {
  double x,y,y1,zz,scale1,cos2,theta1,theta2;
  int i,j,i1=0,k;

  for (j = 0; j < Height; j++) {
    y1 = 2*(2.0*j-Height)/Width/scale;
    if (Math.abs(y1)>=1.0) for (i = 0; i < Width ; i++) pixels[j*Width+i] = SNG.background();
    else {
      zz = Math.sqrt(1.0-y1*y1);
      y = 2.0/Math.PI*(y1*zz+Math.asin(y1));
      cos2 = Math.sqrt(1.0-y*y);
      if (cos2>0.0) {
	SNG.setScaling((scale*Width/Height/cos2/Math.PI), Width, Height);
	for (i = 0; i < Width ; i++) {
	  theta1 = Math.PI/zz*(2.0*i-Width)/Width/scale;
	  if (Math.abs(theta1)>Math.PI) pixels[j*Width+i] = SNG.background();
	  else {
	    theta1 += longi-0.5*Math.PI;
	    pixels[j*Width+i] = SNG.color(Math.cos(theta1)*cos2,y,-Math.sin(theta1)*cos2);
	  }
        }
      }
    }
  }
}
    public void renderLatitudes()
    {
	double x,y,theta1,theta2;
	int i,j,k;

	for (theta1 = 0.0; theta1>-90.0; theta1-=hgrid);
	for (theta1 = theta1; theta1<90.0; theta1+=hgrid)
	{
	    theta2 = Math.abs(theta1);
	    x = Math.floor(theta2/5.0); y = theta2/5.0-x;
	    try {
		y = (1.0-y)*moll_table[(int)x]+y*moll_table[(int)x+1];
	    } catch (ArrayIndexOutOfBoundsException b) {
		y = 1.0;
	    }
	    if (theta1<0.0) y = -y;
	    j = Height/2+(int)(0.25*y*Width*scale);
	    if (j>=0 && j< Height)
	    {
	    for (i = max(0,Width/2-(int)(0.5*Width*scale*Math.sqrt(1.0-y*y)));
		 i < min(Width,Width/2+(int)(0.5*Width*scale*Math.sqrt(1.0-y*y)));
	         i++)
	        pixels[j*Width+i] = SNG.background();
	    }
	}
    }
    public void renderLongitudes()
    {
	double x,y,y1,theta1;
	int i,i1=0,j,k;

	for (theta1 = 0.0; theta1>-360.0; theta1-=vgrid);
	for (theta1 = theta1; theta1<360.0; theta1+=vgrid)
	{
	    if (DEG2RAD*theta1-longi+0.5*Math.PI>-Math.PI &&
	      DEG2RAD*theta1-longi+0.5*Math.PI<=Math.PI)
	    {
		x = 0.5*(DEG2RAD*theta1-longi+0.5*Math.PI)*Width*scale/Math.PI;
		j = max(0,Height/2-(int)(0.25*Width*scale));
		y = 2*(2.0*j-Height)/Width/scale;
		i = (int)(Width/2+x*Math.sqrt(1.0-y*y));
		for (; j <= min(Height,Height/2+(int)(0.25*Width*scale)); j++)
		{
		    y1 = 2*(2.0*j-Height)/Width/scale;
		    if (Math.abs(y1)<=1.0)
		    {
			i1 = (int)(Width/2+x*Math.sqrt(1.0-y1*y1));
			if (i1>0 && i1<=Width) pixels[j*Width+i1] = SNG.background();
		    }
		    if (Math.abs(y)<=1.0)
		    {
			if (i0 && k<=Width) pixels[j*Width+k] = SNG.background();
			}
			else if (i>i1)
			{
			  for (k=i-1; k>i1; k--)
			    if (k>0 && k<=Width) pixels[j*Width+k] = SNG.background();
			}
		    }
		    y = y1;
		    i = i1;
		}
	    }
	}
    }
}
1