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

public class ConicalImageProjection extends ImageProjection
{
    public ConicalImageProjection(int w, int h, SolidNoiseGenerator sng)
    {
	super(w, h, sng);
    }
    double ymin;
    double ymax;
    public void renderTerrain()
    {
	double k1,c,y2,x,y,z,zz,x1,y1,z1,theta1,theta2,cos2;
	int i,j;

	ymin = 2.0;
	ymax = -2.0;
	SNG.setScaling(scale, Width, Height);
	k1 = 1.0/sla;
	c = k1*k1;
	y2 = Math.sqrt(c*(1.0-Math.sin(lat/k1))/(1.0+Math.sin(lat/k1)));

  if (lat>0)
  {
    for (j = 0; j < Height; j++) {
      y = (2.0*j-Height)/Height/scale+y2;
      for (i = 0; i < Width ; i++) {
	x = (2.0*i-Width)/Height/scale;
	zz = x*x+y*y;
	if (zz==0.0) theta1 = 0.0; else theta1 = k1*Math.atan2(x,y);
	if (theta1<-Math.PI || theta1>Math.PI) pixels[j*Width+i] = SNG.background();
	else {
	  theta1 += longi-0.5*Math.PI; /* theta1 is longitude */
	  theta2 = k1*Math.asin((zz-c)/(zz+c));
	  /* theta2 is latitude */
	  if (theta2 > 0.5*Math.PI || theta2 < -0.5*Math.PI) pixels[j*Width+i] = SNG.background();
	  else {
	    cos2 = Math.cos(theta2);
	    y = Math.sin(theta2);
	    if (y < ymin) ymin = y;
	    if (y > ymax) ymax = y;
	    pixels[j*Width+i] = SNG.color(Math.cos(theta1)*cos2,y,-Math.sin(theta1)*cos2);
	  }
        }
      }
    }
  }
  else {
    for (j = 0; j < Height; j++) {
      for (i = 0; i < Width ; i++) {
	x = (2.0*i-Width)/Height/scale;
	y = (2.0*j-Height)/Height/scale-y2;
	zz = x*x+y*y;
	if (zz==0.0) theta1 = 0.0; else theta1 = -k1*Math.atan2(x,-y);
	if (theta1<-Math.PI || theta1>Math.PI) pixels[j*Width+i] = SNG.background();
	else {
	  theta1 += longi-0.5*Math.PI; /* theta1 is longitude */
	  theta2 = k1*Math.asin((zz-c)/(zz+c));
	  /* theta2 is latitude */
	  if (theta2 > 0.5*Math.PI || theta2 < -0.5*Math.PI) pixels[j*Width+i] = SNG.background();
	  else {
	    cos2 = Math.cos(theta2);
	    y = Math.sin(theta2);
	    if (y < ymin) ymin = y;
	    if (y > ymax) ymax = y;
	    pixels[j*Width+i] = SNG.color(Math.cos(theta1)*cos2,y,-Math.sin(theta1)*cos2);
	  }
        }
      }
    }
  }
}
    public void renderLatitudes()
    {
	double c,k1,x,y,z,x1,y1,z1,y2,zz,theta1,theta2;
	int i,j,k;

	k1 = 1.0/Math.sin(lat);
	c = k1*k1;
	y2 = Math.sqrt(c*(1.0-Math.sin(lat/k1))/(1.0+Math.sin(lat/k1)));
	if (lat>0)
	{
	    for (theta1 = 0.0; theta1>-90.0; theta1-=hgrid);
	    for (theta1 = theta1; theta1<90.0; theta1+=hgrid)
	    {
		y = Math.sin(DEG2RAD*theta1);
		if (ymin <= y && y <= ymax)
		{
		    zz = Math.sqrt(c*(1.0+Math.sin(DEG2RAD*theta1/k1))
			/(1.0-Math.sin(DEG2RAD*theta1/k1)));
		    for (theta2=-Math.PI+longi; theta2-90.0; theta1-=hgrid);
	    for (theta1 = theta1; theta1<90.0; theta1+=hgrid)
	    {
		y = Math.sin(DEG2RAD*theta1);
		if (ymin <= y && y <= ymax)
		{
		    zz = Math.sqrt(c*(1.0+Math.sin(DEG2RAD*theta1/k1))
			/(1.0-Math.sin(DEG2RAD*theta1/k1)));
		    for (theta2=-Math.PI+longi; theta20)
	{
	    for (theta1=-0.5*Math.PI; theta1<0.5*Math.PI; theta1+=0.5/Width/scale)
	    {
		y = Math.sin(theta1);
		if (ymin <= y && y <= ymax)
		{
		    zz = Math.sqrt(c*(1.0+Math.sin(theta1/k1)) /(1.0-Math.sin(theta1/k1)));
		    for (theta2 = 0.0; theta2>-180.0+longi/DEG2RAD; theta2-=vgrid);
		    for (theta2 = theta2; theta2<180.0+longi/DEG2RAD; theta2+=vgrid)
		    {
			z1 = DEG2RAD*theta2-longi;
			x1 = -zz*Math.sin(z1/k1);
			y1 = -zz*Math.cos(z1/k1);
			i = (int)(0.5*(Height*scale*x1+Width));
			j = (int)(0.5*(Height*scale*(y1+y2)+Height));
			if (0<=i && i-180.0+longi/DEG2RAD; theta2-=vgrid);
		    for (theta2 = theta2; theta2<180.0+longi/DEG2RAD; theta2+=vgrid)
		    {
			z1 = DEG2RAD*theta2-longi;
			x1 = zz*Math.sin(z1/k1);
			y1 = zz*Math.cos(z1/k1);
			i = (int)(0.5*(Height*scale*x1+Width));
			j = (int)(0.5*(Height*scale*(y1-y2)+Height));
			if (0<=i && i




1