/** Tworzenie czasteczki.. */
void SnowEmitter::createNewParticle(Window* _window) {
	for (usint i = 0; i < getIntRandom(2, (int) (50 * (50.f / (float) delay)));
			++i) {
		float angle = getIntRandom<int>(20, 80);
		float speed = 1.f;
		
		Vector<float> wind(
				cos(TO_RAD(angle)) * speed,
				sin(TO_RAD(angle)) * speed);
		
		Particle part(
				Vector<float>(x, y),
				getIntRandom(6, 14),
				getIntRandom(50, 100),
				oglWrapper::WHITE);
		
		part.velocity = wind;
		part.angle = angle;
		
		part.velocity.y += getIntRandom(150, 350) / 150;
		part.pos.x = x + getIntRandom(-100, (int) w + 100);
		
		particles.push_back(part);
	}
}
Beispiel #2
0
int bot_gps_linearize_to_xy(BotGPSLinearize *gl, const double ll_deg[2], double xy[2])
{
    double dlat = TO_RAD(ll_deg[0] - gl->lat0_deg);
    double dlon = TO_RAD(ll_deg[1] - gl->lon0_deg);

    xy[0] = sin(dlon) * gl->radius_ew * cos(TO_RAD(gl->lat0_deg));
    xy[1] = sin(dlat) * gl->radius_ns;
    
    return 0;
}
Beispiel #3
0
double distance_vincenty(const double lat1, const double lon1, const double lat2, const double lon2, char *is_null)
{
  const double a = 6378137.0f, b = 6356752.3142f,  f = 1.0f / 298.257223563f;  // WGS-84 ellipsiod

  double L = TO_RAD(fabs(lon2-lon1));
  double U1 = atan((1.0f-f) * tan(TO_RAD(lat1)));
  double U2 = atan((1.0f-f) * tan(TO_RAD(lat2)));
  double sinU1 = sin(U1), cosU1 = cos(U1);
  double sinU2 = sin(U2), cosU2 = cos(U2);

  double lambda = L, lambdaP;
  double sinLambda, cosLambda, sinSigma, sigma, cosSigma, sinAlpha, cosSqAlpha, cos2SigmaM;
  int iterLimit = 0;

  *is_null = 0x00;

  do {
    sinLambda = sin(lambda);
    cosLambda = cos(lambda);
    sinSigma = sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
      (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
    if (sinSigma==0.0f) {
        return 0.0f;  // co-incident points
    }
    cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
    sigma = atan2(sinSigma, cosSigma);
    sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
    cosSqAlpha = 1.00f - sinAlpha*sinAlpha;

    // equatorial line: cosSqAlpha=0 (§6)
    if (cosSqAlpha == 0.0f) cos2SigmaM = 0.0f;
    else cos2SigmaM = cosSigma - (2.0f*sinU1*sinU2/cosSqAlpha);

    double C = f/16.0f * cosSqAlpha*(4.0f + f * (4.0f - (3.0f*cosSqAlpha)));
    lambdaP = lambda;
    lambda = L + (1.0f-C) * f * sinAlpha *
      (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1.0f+2.0f*cos2SigmaM*cos2SigmaM)));
  } while (fabs(lambda-lambdaP) > 1.0e-12f && ++iterLimit<20);

  if (iterLimit==20) {
      *is_null = 0x01;
      return 0.0f; // formula failed to converge
  }

  double uSq = cosSqAlpha * (a*a - b*b) / (b*b);
  double A = 1.0f + uSq/16384.0f*(4096.0f+uSq*(-768.0f+uSq*(320.0f-175.0f*uSq)));
  double B = uSq/1024.0f * (256.0f+uSq*(-128.0f+uSq*(74.0f-47.0f*uSq)));
  double deltaSigma = B*sinSigma*(cos2SigmaM+B/4.0f*(cosSigma*(-1.0f+2.0f*cos2SigmaM*cos2SigmaM)-
    B/6.0f*cos2SigmaM*(-3.0f+4.0f*sinSigma*sinSigma)*(-3.0f+4.0f*cos2SigmaM*cos2SigmaM)));

  return b*A*(sigma-deltaSigma);
}
void PutGrid(BITMAP * dc)
{
	double yr = TO_RAD(Form1->TrackBarTilt->Position);
	float sin_y = Sin(ANGLE_Y);
	float cos_y = Cos(ANGLE_Y);

	float ScaleV_Y = sin_y;
	float ScaleV_XZ = cos_y;
	float sin_x = Sin(ANGLE_X);
	float cos_x = Cos(ANGLE_X);
	int PenCol;
	SET_PEN(dc,128,0,0);
	LINE(dc,CENTER+XGRID*cos_x,CENTER-XGRID*sin_x*ScaleV_XZ-XGRID_2*ScaleV_Y,
			CENTER-XGRID*cos_x,CENTER+XGRID*sin_x*ScaleV_XZ-XGRID_2*ScaleV_Y,PenCol);
	LINE(dc,CENTER+XGRID*cos_x,CENTER-XGRID*sin_x*ScaleV_XZ,
			CENTER-XGRID*cos_x,CENTER+XGRID*sin_x*ScaleV_XZ,PenCol);
	LINE(dc,CENTER+XGRID*cos_x,CENTER-XGRID*sin_x*ScaleV_XZ+XGRID_2*ScaleV_Y,
			CENTER-XGRID*cos_x,CENTER+XGRID*sin_x*ScaleV_XZ+XGRID_2*ScaleV_Y,PenCol);

	LINE(dc	,CENTER+XGRID*cos_x,CENTER-XGRID*sin_x*ScaleV_XZ-XGRID_2*ScaleV_Y
			,CENTER+XGRID*cos_x,CENTER-XGRID*sin_x*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);
	LINE(dc	,CENTER+XGRID_2*cos_x,CENTER-XGRID_2*sin_x*ScaleV_XZ-XGRID_2*ScaleV_Y
			,CENTER+XGRID_2*cos_x,CENTER-XGRID_2*sin_x*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);
	LINE(dc	,CENTER-XGRID*cos_x,CENTER+XGRID*sin_x*ScaleV_XZ-XGRID_2*ScaleV_Y
			,CENTER-XGRID*cos_x,CENTER+XGRID*sin_x*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);
	LINE(dc	,CENTER-XGRID_2*cos_x,CENTER+XGRID_2*sin_x*ScaleV_XZ-XGRID_2*ScaleV_Y
			,CENTER-XGRID_2*cos_x,CENTER+XGRID_2*sin_x*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);

	float sin_z = cos_x;//Sin(ANGLE_Z);
	float cos_z = sin_x;//Cos(ANGLE_Z);

	SET_PEN(dc,0,96,96);//                SelectObject(dc,PenYellow);
	LINE(dc,CENTER-XGRID*cos_z, CENTER - XGRID*sin_z*ScaleV_XZ - XGRID_2*ScaleV_Y,
			CENTER+XGRID*cos_z, CENTER + XGRID*sin_z*ScaleV_XZ - XGRID_2*ScaleV_Y,PenCol);
	LINE(dc,CENTER-XGRID*cos_z, CENTER - XGRID*sin_z*ScaleV_XZ,//*ScaleV_Y    ,
			CENTER+XGRID*cos_z, CENTER + XGRID*sin_z*ScaleV_XZ /**ScaleV_Y*/    ,PenCol);
	LINE(dc,CENTER-XGRID*cos_z, CENTER - XGRID*sin_z*ScaleV_XZ +XGRID_2*ScaleV_Y,
			CENTER+XGRID*cos_z, CENTER + XGRID*sin_z*ScaleV_XZ +XGRID_2*ScaleV_Y,PenCol);

	LINE(dc,CENTER+XGRID*cos_z, CENTER + XGRID*sin_z*ScaleV_XZ-XGRID_2*ScaleV_Y
		   ,CENTER+XGRID*cos_z, CENTER + XGRID*sin_z*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);
	LINE(dc	,CENTER-XGRID_2*cos_z,CENTER-XGRID_2*sin_z*ScaleV_XZ-XGRID_2*ScaleV_Y
			,CENTER-XGRID_2*cos_z,CENTER-XGRID_2*sin_z*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);
	LINE(dc,CENTER-XGRID*cos_z, CENTER - XGRID*sin_z*ScaleV_XZ-XGRID_2*ScaleV_Y
		   ,CENTER-XGRID*cos_z, CENTER - XGRID*sin_z*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);
	LINE(dc	,CENTER+XGRID_2*cos_z,CENTER+XGRID_2*sin_z*ScaleV_XZ-XGRID_2*ScaleV_Y
			,CENTER+XGRID_2*cos_z,CENTER+XGRID_2*sin_z*ScaleV_XZ+XGRID_2*ScaleV_Y			,PenCol);

	SET_PEN(dc,64,64,64);//                SelectObject(dc,PenYellow);
	LINE(dc,CENTER,CENTER-XGRID_2*ScaleV_Y,
			CENTER,CENTER+XGRID_2*ScaleV_Y,PenCol);
	circlefill(dc,
			CENTER+XGRID*cos_z, CENTER + XGRID*sin_z*ScaleV_XZ //*sin_y
			,3,makecol24(0,128,0));
	circlefill(dc,
			CENTER,CENTER-XGRID_2*ScaleV_Y
			,3,makecol24(128,128,0));
}
Beispiel #5
0
int bot_gps_linearize_to_lat_lon(BotGPSLinearize *gl, const double xy[2], double ll_deg[2])
{
    double dlat = asin(xy[1] / gl->radius_ns);
    ll_deg[0] = TO_DEG(dlat) + gl->lat0_deg;

    double dlon = asin(xy[0] / gl->radius_ew / cos(TO_RAD(gl->lat0_deg)));
    ll_deg[1] = TO_DEG(dlon) + gl->lon0_deg;

    return 0;
}
Beispiel #6
0
void Player::fire()
{
    double phi = TO_RAD(myTank->turret.getRotation());
    double sin = std::sin(phi) , cos = std::cos(phi);
    double TankVelocity = power*500;
    Missile *m=new Missile(myTank->turret.getPosition().x + myTank->turret.getLocalBounds().width * cos,
                             myTank->turret.getPosition().y + myTank->turret.getLocalBounds().width * sin);
    m->setVelocity(TankVelocity * cos, TankVelocity * sin);
    Application::getGame().addWorldObj(m);
    Application::getMsgStream().sendMessage(Message("PlayerTurnOver"),"GameState");
}
Beispiel #7
0
void KalmanModel::Initialize(float x, float y, float phi, float e1, float e2, float e3, float w , bool a){

    active = a;
    // State initialization  
    state.zero();  
    state(0,0) = x;
    state(1,0) = y;
    state(2,0) = phi;
    state(3,0) = e1;
    state(4,0) = e2;
    state(5,0) = e3;
    mWeight = w;

    // Variance initialization
    var.zero();

    var(0,0) = 0.4 * 0.4;
    var(1,1) = 0.1 * 0.1;
    var(2,2) = TO_RAD(10) * TO_RAD(10);

    var(3,3) = 0.025;
    var(4,4) = 0.025;
    var(5,5) = 0.025;
}
Beispiel #8
0
void bot_gps_linearize_init(BotGPSLinearize *gl, const double ll_deg[2])
{
    gl->lat0_deg = ll_deg[0];
    gl->lon0_deg = ll_deg[1];

    double lat_rad = TO_RAD(ll_deg[0]);

    // this is the best radius approximation, agnostic of direction
    // we don't use this anymore.
    //    gl->radius = REQ*REQ*RPO / (SQ(REQ*cos(lat_rad)) + SQ(RPO*sin(lat_rad)));

    // best radius approximation in ns and ew direction.
    gl->radius_ns = SQ(REQ*RPO) / pow((SQ(REQ*cos(lat_rad))) + SQ(RPO*sin(lat_rad)), 1.5);
    gl->radius_ew = REQ*REQ / sqrt(SQ(REQ*cos(lat_rad)) + SQ(RPO*sin(lat_rad)));
}
Beispiel #9
0
float CalcDist(float La1, float Lo1, float La2, float Lo2) {
    const float R = 6371.0f;

    float RLa1 = TO_RAD(La1);
    float RLa2 = TO_RAD(La2);
    float RLo1 = TO_RAD(Lo1);
    float RLo2 = TO_RAD(Lo2);

    float DLat = TO_RAD(La2-La1);
    float DLon = TO_RAD(Lo2-Lo1);

    float X = DLon*wCos((RLa1+RLa2)*0.5f);
    float Y = DLat;
    float D = fSqrt(X*X + Y*Y)*R;

    return D;
}
inline double TILT_ANGLE()
{
	return TO_RAD(Form1->TrackBarTilt->Position);
}
inline double ROT_ANGLE()
{
	return TO_RAD(Form1->TrackBarRot->Position);
}
Beispiel #12
0
int seccurved::updateSection(int)
{
    length = 0.0;
    int numNodes = 1;
    float fRiddenAngle = 0.0;
    float artificialRoll = 0.0;

    fAngle = getMaxArgument();

    int sizediff = lNodes.size() - lAngles.size();
    for(int i = 0; i <= sizediff; ++i) {
        lAngles.append(0.f);
    }
    lAngles[0] = 0.f;
	lNodes[0].updateNorm();

	float diff = lNodes[0].fRollSpeed; // - rollFunc->funcList.at(0)]-startValue;
    if(bOrientation == 1) {
		diff += glm::dot(lNodes[0].vDir, glm::vec3(0.f, 1.f, 0.f))*lNodes[0].getYawChange();
    }
    rollFunc->funcList.at(0)->translateValues(diff);
    rollFunc->translateValues(rollFunc->funcList.at(0));

    mnode* leadOutNode = NULL;
    float myLeadOut = 0.f;

    while(fRiddenAngle < fAngle - std::numeric_limits<float>::epsilon()) {
        float deltaAngle, fTrans;

		mnode* prevNode = &lNodes[numNodes-1];

        deltaAngle = prevNode->fVel / fRadius / F_HZ * 180/F_PI;

		if(fLeadIn > 0.f && (fTrans = (prevNode->fTotalLength - lNodes[0].fTotalLength)/(1.997f/F_HZ*prevNode->fVel/deltaAngle * fLeadIn)) <= 1.f) {
            deltaAngle *= fTrans*fTrans*(3+fTrans*(-2));
        }

        if(leadOutNode == NULL && fRiddenAngle > fAngle-fLeadOut) {
            leadOutNode = prevNode;
            myLeadOut = fAngle - fRiddenAngle;
        }
        if(leadOutNode && fLeadOut > 0.f) {
            if((fTrans = 1.f-(prevNode->fTotalLength - leadOutNode->fTotalLength)/(1.997f/F_HZ*prevNode->fVel/deltaAngle * myLeadOut)) >= 0.f) {
                deltaAngle *= fTrans*fTrans*(3+fTrans*(-2));
            } else {
                break;
            }
        }

		fRiddenAngle += deltaAngle;
		if(numNodes >= lNodes.size()) {
			lNodes.append(*prevNode);
			lAngles.append(fRiddenAngle);
		} else {
			lAngles[numNodes] = fRiddenAngle;
		}

		mnode* curNode = &lNodes[numNodes];
		prevNode = &lNodes[numNodes-1]; // in case vector gets copied

        if(curNode->fVel < 0.1f) {
            qWarning("train goes very slowly");
            break;
        }

        curNode->updateNorm();

        float fPureDirection = fDirection - artificialRoll; //- curNode->fRoll;

        curNode->vDir = glm::angleAxis(TO_RAD(deltaAngle), (float)glm::cos(-fPureDirection*F_PI/180) * prevNode->vLat  + (float)glm::sin(-fPureDirection*F_PI/180) * prevNode->vNorm)*prevNode->vDir;
        curNode->vLat = glm::angleAxis(TO_RAD(deltaAngle), (float)glm::cos(-fPureDirection*F_PI/180) * prevNode->vLat  + (float)glm::sin(-fPureDirection*F_PI/180) * prevNode->vNorm)*prevNode->vLat;
        curNode->vDir = glm::normalize(curNode->vDir);
        curNode->vLat = glm::normalize(curNode->vLat);

        curNode->updateNorm();


        curNode->vPos += curNode->vDir*(curNode->fVel/(2.f*F_HZ)) + prevNode->vDir*(curNode->fVel/(2.f*F_HZ)) + (prevNode->vPosHeart(parent->fHeart) - curNode->vPosHeart(parent->fHeart));


        curNode->setRoll(rollFunc->getValue(fRiddenAngle)/F_HZ);
        curNode->fRollSpeed = rollFunc->getValue(fRiddenAngle);
        artificialRoll += rollFunc->getValue(fRiddenAngle)/F_HZ;

        if(bOrientation == EULER) {
            calcDirFromLast(numNodes);
			lNodes[numNodes].setRoll(glm::dot(lNodes[numNodes].vDir, glm::vec3(0.f, -1.f, 0.f))*lNodes[numNodes].fYawFromLast);
			artificialRoll += glm::dot(lNodes[numNodes].vDir, glm::vec3(0.f, -1.f, 0.f))*lNodes[numNodes].fYawFromLast;
			curNode->fRollSpeed += glm::dot(lNodes[numNodes].vDir, glm::vec3(0.f, -1.f, 0.f))*lNodes[numNodes].fYawFromLast*F_HZ;
        }

        curNode->updateNorm();

        if(bSpeed) {
            curNode->fEnergy -= (curNode->fVel*curNode->fVel*curNode->fVel/F_HZ * parent->fResistance);
            curNode->fVel = sqrt(2.f*(curNode->fEnergy-F_G*(curNode->vPosHeart(parent->fHeart*0.9f).y+curNode->fTotalLength*parent->fFriction)));
        } else {
            curNode->fVel = this->fVel;
            curNode->fEnergy = 0.5*fVel*fVel + F_G*(curNode->vPosHeart(parent->fHeart*0.9f).y + curNode->fTotalLength*parent->fFriction);
        }

        //curNode->vPos = glm::vec3(glm::translate(glm::rotate(glm::translate(vCenter), fAngle/numNodes, (float)glm::cos(-fDirection*F_PI/180) * curNode->vLat  + (float)glm::sin(-fDirection*F_PI/180) * prevNode->vNorm), -vCenter)*glm::vec4(prevNode->vPos, 1));

		curNode->updateRoll();

		curNode->fDistFromLast = glm::distance(curNode->vPosHeart(parent->fHeart), prevNode->vPosHeart(parent->fHeart));
		curNode->fTotalLength = prevNode->fTotalLength + curNode->fDistFromLast;
        curNode->fHeartDistFromLast = glm::distance(curNode->vPos, prevNode->vPos);
		curNode->fTotalHeartLength = prevNode->fTotalHeartLength + curNode->fHeartDistFromLast;

        calcDirFromLast(numNodes);

		float temp = cos(fabs(lNodes[numNodes].getPitch())*F_PI/180.f);
        float forceAngle = sqrt(temp*temp*curNode->fYawFromLast*curNode->fYawFromLast + curNode->fPitchFromLast*curNode->fPitchFromLast);//deltaAngle;
        curNode->fAngleFromLast = forceAngle;

        glm::vec3 forceVec;
        if(fabs(curNode->fAngleFromLast) < std::numeric_limits<float>::epsilon()) {
            forceVec = glm::vec3(0.f, 1.f, 0.f);
        } else {
            float normalDAngle = F_PI/180.f*(- curNode->fPitchFromLast * cos(curNode->fRoll*F_PI/180.) - temp*curNode->fYawFromLast*sin(curNode->fRoll*F_PI/180.));
            float lateralDAngle = F_PI/180.f*(curNode->fPitchFromLast * sin(curNode->fRoll*F_PI/180.) - temp*curNode->fYawFromLast*cos(curNode->fRoll*F_PI/180.));

            forceVec = glm::vec3(0.f, 1.f, 0.f) + lateralDAngle*curNode->fVel*F_HZ/F_G * curNode->vLat + normalDAngle*curNode->fHeartDistFromLast*F_HZ*F_HZ/F_G * curNode->vNorm;
        }

        curNode->forceNormal = - glm::dot(forceVec, glm::normalize(curNode->vNorm));
        curNode->forceLateral = - glm::dot(forceVec, glm::normalize(curNode->vLat));

        numNodes++;
    }

	while(lNodes.size() > numNodes) {
		lNodes.removeLast();
		lAngles.removeLast();
	}

    if(fLeadOut > 0.0001f) {
		lNodes.last().fAngleFromLast = 0.f;
		lNodes.last().fPitchFromLast = 0.f;
		lNodes.last().fYawFromLast = 0.f;
    }
	if(lNodes.size()) length = lNodes.last().fTotalLength - lNodes.first().fTotalLength;
    else length = 0;
    return 0;
}
Beispiel #13
0
/* ======================================================= *\ 
 * PIE
 * 
 * Notes:
 *  always drawn from 12:00 position clockwise
 *  'missing' slices don't get labels
 *  sum(val[0], ... val[num_points-1]) is assumed to be 100%
\* ======================================================= */
void
GDC_out_pie( short			IMGWIDTH,
			 short			IMGHEIGHT,
			 FILE			*img_fptr,			/* open file pointer */
			 GDCPIE_TYPE	type,
			 int			num_points,
			 char			*lbl[],				/* data labels */
			 float			val[] )				/* data */
{
	int			i;

	gdImagePtr	im;
	int			BGColor,
				LineColor,
				PlotColor,
				EdgeColor,
				EdgeColorShd;
	CREATE_ARRAY1( SliceColor, int, num_points );		/* int SliceColor[num_points] */
	CREATE_ARRAY1( SliceColorShd, int, num_points );	/* int SliceColorShd[num_points] */

	float		rad = 0.0;					/* radius */
	float		ellipsex = 1.0;
	float		ellipsey = 1.0 - (float)GDCPIE_perspective/100.0;
	float		tot_val = 0.0;
	float		pscl;
	int			cx,							/* affects PX() */
				cy;							/* affects PY() */
								/* ~ 1% for a size of 100 pixs */
								/* label sizes will more dictate this */
	float		min_grphable = ( GDCPIE_other_threshold < 0?
								  100.0/(float)MIN(IMGWIDTH,IMGHEIGHT):
								  (float)GDCPIE_other_threshold )/100.0;
	short		num_slices1 = 0,
				num_slices2 = 0;
	char		any_too_small = FALSE;
	CREATE_ARRAY1( others, char, num_points );			/* char others[num_points] */
	CREATE_ARRAY2( slice_angle, float, 3, num_points );	/* float slice_angle[3][num_points] */
														/* must be used with others[] */
	char		threeD = ( type == GDC_3DPIE );

	int			xdepth_3D      = 0,			/* affects PX() */
				ydepth_3D      = 0;			/* affects PY() */
	int			do3Dx = 0,					/* reserved for macro use */
				do3Dy = 0;

	CREATE_ARRAY2( pct_lbl, char, num_points, 16 );			/* sizeof or strlen (GDCPIE_percent_fmt)? */
	CREATE_ARRAY1( pct_ftsz, struct fnt_sz_t, num_points );	/* struct fnt_sz_t lbl_ftsz[num_points] */
	CREATE_ARRAY1( lbl_ftsz, struct fnt_sz_t, num_points );	/* struct fnt_sz_t lbl_ftsz[num_points] */


#ifdef HAVE_LIBFREETYPE
	char			*gdcpie_title_font  = GDCPIE_title_font;
	char			*gdcpie_label_font  = GDCPIE_label_font;
	double			gdcpie_title_ptsize = GDCPIE_title_ptsize;
	double			gdcpie_label_ptsize = GDCPIE_label_ptsize;
#else
	char			*gdcpie_title_font  = NULL;
	char			*gdcpie_label_font  = NULL;
	double			gdcpie_title_ptsize = 0.0;
	double			gdcpie_label_ptsize = 0.0;
#endif

/*	GDCPIE_3d_angle = MOD_360(90-GDCPIE_3d_angle+360); */
	pie_3D_rad = TO_RAD( GDCPIE_3d_angle );

	xdepth_3D      = threeD? (int)( cos((double)MOD_2PI(M_PI_2-pie_3D_rad+2.0*M_PI)) * GDCPIE_3d_depth ): 0;
	ydepth_3D      = threeD? (int)( sin((double)MOD_2PI(M_PI_2-pie_3D_rad+2.0*M_PI)) * GDCPIE_3d_depth ): 0;
/*	xdepth_3D      = threeD? (int)( cos(pie_3D_rad) * GDCPIE_3d_depth ): 0; */
/*	ydepth_3D      = threeD? (int)( sin(pie_3D_rad) * GDCPIE_3d_depth ): 0; */

	load_font_conversions();

	/* ----- get total value ----- */
	for( i=0; i<num_points; ++i )
		tot_val += val[i];

	/* ----- pie sizing ----- */
	/* ----- make width room for labels, depth, etc.: ----- */
	/* ----- determine pie's radius ----- */
	{
	int		title_hgt  = GDCPIE_title? 1			/*  title? horizontal text line */
									   + GDCfnt_sz( GDCPIE_title,
													GDCPIE_title_size,
													gdcpie_title_font, gdcpie_title_ptsize, 0.0, NULL ).h

									   + 2:
									   0;
	float	last = 0.0;
	float	label_explode_limit = 0.0;
	int		cheight,
			cwidth;

	/* maximum: no labels, explosions */
	/* gotta start somewhere */
	rad = (float)MIN( (IMGWIDTH/2)/ellipsex-(1+ABS(xdepth_3D)), (IMGHEIGHT/2)/ellipsey-(1+ABS(ydepth_3D))-title_hgt );

	/* ok fix center, i.e., no floating re labels, explosion, etc. */
	cx = IMGWIDTH/2 /* - xdepth_3D */ ;
	cy = (IMGHEIGHT-title_hgt)/2 + title_hgt /* + ydepth_3D */ ;

	cheight = (IMGHEIGHT- title_hgt)/2 /* - ydepth_3D */ ;
	cwidth  = cx;

	/* walk around pie. determine spacing to edge */
	for( i=0; i<num_points; ++i )
		{
		float	this_pct = val[i]/tot_val;						/* should never be > 100% */
		float	this = this_pct*(2.0*M_PI);						/* pie-portion */
		if( (this_pct > min_grphable) ||						/* too small */
			(!GDCPIE_missing || !GDCPIE_missing[i]) )			/* still want angles */
			{
			int this_explode = GDCPIE_explode? GDCPIE_explode[i]: 0;
			double	this_sin;
			double	this_cos;
			slice_angle[0][i] = this/2.0+last;				/* mid-point on full pie */
			slice_angle[1][i] = last;						/* 1st on full pie */
			slice_angle[2][i] = this+last;					/* 2nd on full pie */
			this_sin        = ellipsex*sin( (double)slice_angle[0][i] );
			this_cos        = ellipsey*cos( (double)slice_angle[0][i] );

			if( !GDCPIE_missing || !(GDCPIE_missing[i]) )
				{
				short	lbl_wdth = 0,
						lbl_hgt  = 0;
				float	this_y_explode_limit,
						this_x_explode_limit;

				/* start slice label height, width     */
				/*  accounting for PCT placement, font */
				pct_ftsz[i].h = 0;
				pct_ftsz[i].w = 0;
				if( GDCPIE_percent_fmt &&
					GDCPIE_percent_labels != GDCPIE_PCT_NONE )
					{
					sprintf( pct_lbl[i], GDCPIE_percent_fmt, this_pct * 100.0 );
					pct_ftsz[i] = GDCfnt_sz( pct_lbl[i],
											 GDCPIE_label_size,
											 gdcpie_label_font, gdcpie_label_ptsize, 0.0, NULL );
					lbl_wdth = pct_ftsz[i].w;
					lbl_hgt  = pct_ftsz[i].h;
					}

				if( lbl && lbl[i] )
					{
					lbl_ftsz[i] = GDCfnt_sz( lbl[i],
											 GDCPIE_label_size,
											 gdcpie_label_font, gdcpie_label_ptsize, 0.0, NULL );

					if( GDCPIE_percent_labels == GDCPIE_PCT_ABOVE ||
						GDCPIE_percent_labels == GDCPIE_PCT_BELOW )
						{
						lbl_wdth = MAX( pct_ftsz[i].w, lbl_ftsz[i].w );
						lbl_hgt  = pct_ftsz[i].h + lbl_ftsz[i].h + 1;
						}
					else
					if( GDCPIE_percent_labels == GDCPIE_PCT_RIGHT ||
						GDCPIE_percent_labels == GDCPIE_PCT_LEFT )
						{
						lbl_wdth = pct_ftsz[i].w + lbl_ftsz[i].w + 1;
						lbl_hgt  = MAX( pct_ftsz[i].h, lbl_ftsz[i].h );
						}
					else /* GDCPIE_PCT_NONE */
						{
						lbl_wdth = lbl_ftsz[i].w;
						lbl_hgt  = lbl_ftsz[i].h;
						}
					}
				else
					lbl_wdth = lbl_hgt = 0;
				/* end label height, width */
				
				/* diamiter limited by this point's: explosion, label                 */
				/* (radius to box @ slice_angle) - (explode) - (projected label size) */
				/* radius constraint due to labels */
				this_y_explode_limit = (float)this_cos==0.0? FLT_MAX:
										(	(float)( (double)cheight/ABS(this_cos) ) - 
											(float)( this_explode + (lbl&&lbl[i]? GDCPIE_label_dist: 0) ) -
											(float)( lbl_hgt/2 ) / (float)ABS(this_cos)	);
				this_x_explode_limit = (float)this_sin==0.0? FLT_MAX:
										(	(float)( (double)cwidth/ABS(this_sin) ) - 
											(float)( this_explode + (lbl&&lbl[i]? GDCPIE_label_dist: 0) ) -
											(float)( lbl_wdth ) / (float)ABS(this_sin)	);

				rad = MIN( rad, this_y_explode_limit );
				rad = MIN( rad, this_x_explode_limit );

				/* ok at this radius (which is most likely larger than final) */
				/* adjust for inter-label spacing */
/*				if( lbl[i] && *lbl[i] ) */
/*					{ */
/*					char which_edge = slice_angle[0][i] > M_PI? +1: -1;		// which semi */
/*					last_label_yedge = cheight - (int)( (rad +				// top or bottom of label */
/*														(float)(this_explode + */
/*														(float)GDCPIE_label_dist)) * (float)this_cos ) + */
/*											     ( (GDC_fontc[GDCPIE_label_size].h+1)/2 + */
/*													GDC_label_spacing )*which_edge; */
/*					} */

				/* radius constriant due to exploded depth */
				/* at each edge of the slice, and the middle */
				/* this is really stupid */
				/*  this section uses a different algorithm then above, but does the same thing */
				/*  could be combined, but each is ugly enough! */
/* PROTECT /0 */
				if( threeD )
					{
					short	j;
					int		this_y_explode_pos;
					int		this_x_explode_pos;

					/* first N E S W (actually no need for N) */
					if( (slice_angle[1][i] < M_PI_2 && M_PI_2 < slice_angle[2][i]) &&				/* E */
						(this_x_explode_pos=OX(i,M_PI_2,1)) > cx+cwidth )
						rad -= (float)ABS( (double)(1+this_x_explode_pos-(cx+cwidth))/sin(M_PI_2) );
					if( (slice_angle[1][i] < 3.0*M_PI_2 && 3.0*M_PI_2 < slice_angle[2][i]) &&		/* W */
						(this_x_explode_pos=OX(i,3.0*M_PI_2,1)) < cx-cwidth )
						rad -= (float)ABS( (double)(this_x_explode_pos-(cx+cwidth))/sin(3.0*M_PI_2) );
					if( (slice_angle[1][i] < M_PI && M_PI < slice_angle[2][i]) &&					/* S */
						(this_y_explode_pos=OY(i,M_PI,1)) > cy+cheight )
						rad -= (float)ABS( (double)(1+this_y_explode_pos-(cy+cheight))/cos(M_PI) );

					for( j=0; j<3; ++j )
						{
						this_y_explode_pos = IY(i,j,1);
						if( this_y_explode_pos < cy-cheight )
							rad -= (float)ABS( (double)((cy-cheight)-this_y_explode_pos)/cos((double)slice_angle[j][i]) );
						if( this_y_explode_pos > cy+cheight )
							rad -= (float)ABS( (double)(1+this_y_explode_pos-(cy+cheight))/cos((double)slice_angle[j][i]) );

						this_x_explode_pos = IX(i,j,1);
						if( this_x_explode_pos < cx-cwidth )
							rad -= (float)ABS( (double)((cx-cwidth)-this_x_explode_pos)/sin((double)slice_angle[j][i]) );
						if( this_x_explode_pos > cx+cwidth )
							rad -= (float)ABS( (double)(1+this_x_explode_pos-(cx+cwidth))/sin((double)slice_angle[j][i]) );
						}
					}
				}
			others[i] = FALSE;
			}
		else
			{
			others[i] = TRUE;
			slice_angle[0][i] = -FLT_MAX;
			}
		last += this;
		}
	}

	/* ----- go ahead and start the image ----- */
	im = gdImageCreate( IMGWIDTH, IMGHEIGHT );

	/* --- allocate the requested colors --- */
	BGColor   = clrallocate( im, GDCPIE_BGColor );
	LineColor = clrallocate( im, GDCPIE_LineColor );
	PlotColor = clrallocate( im, GDCPIE_PlotColor );
	if( GDCPIE_EdgeColor != GDC_NOCOLOR )
	 {
	 EdgeColor = clrallocate( im, GDCPIE_EdgeColor );
	 if( threeD )
	  EdgeColorShd = clrshdallocate( im, GDCPIE_EdgeColor );
	 }

	/* --- set color for each slice --- */
	for( i=0; i<num_points; ++i )
		if( GDCPIE_Color )
			{
			unsigned long	slc_clr = GDCPIE_Color[i];

			SliceColor[i]     = clrallocate( im, slc_clr );
			if( threeD )
			 SliceColorShd[i] = clrshdallocate( im, slc_clr );
			}
		else
			{
			SliceColor[i]     = PlotColor;
			if( threeD )
			 SliceColorShd[i] = clrshdallocate( im, GDCPIE_PlotColor );
			}

	pscl = (2.0*M_PI)/tot_val;
	
	/* ----- calc: smallest a slice can be ----- */
	/* 1/2 circum / num slices per side. */
	/*              determined by number of labels that'll fit (height) */
	/* scale to user values */
	/* ( M_PI / (IMGHEIGHT / (SFONTHGT+1)) ) */
/*	min_grphable = tot_val / */
/*				   ( 2.0 * (float)IMGHEIGHT / (float)(SFONTHGT+1+TFONTHGT+2) ); */


	if( threeD )
		{
		/* draw background shaded pie */
		{
		float	rad1 = rad * 3.0/4.0;
		for( i=0; i<num_points; ++i )
			if( !(others[i]) &&
				(!GDCPIE_missing || !GDCPIE_missing[i]) )
				{
				int		edge_color = GDCPIE_EdgeColor == GDC_NOCOLOR? SliceColorShd[i]:
				                                                      EdgeColorShd;

				gdImageLine( im, CX(i,1), CY(i,1), IX(i,1,1), IY(i,1,1), edge_color );
				gdImageLine( im, CX(i,1), CY(i,1), IX(i,2,1), IY(i,2,1), edge_color );
				gdImageArc( im, CX(i,1), CY(i,1),
								(int)(rad*ellipsex*2.0), (int)(rad*ellipsey*2.0),
								TO_INT_DEG_FLOOR(slice_angle[1][i])+270,
								TO_INT_DEG_CEIL(slice_angle[2][i])+270,
								edge_color );
					
/*				gdImageFilledArc( im, CX(i,1), CY(i,1), */
/*									  rad*ellipsex*2, rad*ellipsey*2, */
/*									  TO_INT_DEG_FLOOR(slice_angle[1][i])+270, */
/*									  TO_INT_DEG_CEIL(slice_angle[2][i])+270, */
/*									  SliceColorShd[i], */
/*									  gdPie ); */
				/* attempt to fill, if slice is wide enough */
				if( (ABS(IX(i,1,1)-IX(i,2,1)) + ABS(IY(i,1,1)-IY(i,2,1))) > 2 )
					{
					float	rad = rad1;										/* local override */
					gdImageFillToBorder( im, IX(i,0,1), IY(i,0,1), edge_color, SliceColorShd[i] );
					}
				}
		}
		/* fill in connection to foreground pie */
		/* this is where we earn our keep */
		{
		int					t,
							num_slice_angles = 0;
		CREATE_ARRAY1( tmp_slice, struct tmp_slice_t, 4*num_points+4 );		/* should only need 2*num_points+2 */

		for( i=0; i<num_points; ++i )
			if( !GDCPIE_missing || !GDCPIE_missing[i] )
				{
				if( RAD_DIST1(slice_angle[1][i]) < RAD_DIST2(slice_angle[0][i]) )
					tmp_slice[num_slice_angles].hidden = FALSE;
				else
					tmp_slice[num_slice_angles].hidden = TRUE;
				tmp_slice[num_slice_angles].i       = i;
				tmp_slice[num_slice_angles].slice   = slice_angle[0][i];
				tmp_slice[num_slice_angles++].angle = slice_angle[1][i];
				if( RAD_DIST1(slice_angle[2][i]) < RAD_DIST2(slice_angle[0][i]) )
					tmp_slice[num_slice_angles].hidden = FALSE;
				else
					tmp_slice[num_slice_angles].hidden = TRUE;
				tmp_slice[num_slice_angles].i       = i;
				tmp_slice[num_slice_angles].slice   = slice_angle[0][i];
				tmp_slice[num_slice_angles++].angle = slice_angle[2][i];
				/* identify which 2 slices (i) have a tangent parallel to depth angle  */
				if( slice_angle[1][i]<MOD_2PI(pie_3D_rad+M_PI_2) && slice_angle[2][i]>MOD_2PI(pie_3D_rad+M_PI_2) )
					{
					tmp_slice[num_slice_angles].i       = i;
					tmp_slice[num_slice_angles].hidden  = FALSE;
					tmp_slice[num_slice_angles].slice   = slice_angle[0][i];
					tmp_slice[num_slice_angles++].angle = MOD_2PI( pie_3D_rad+M_PI_2 );
					}
				if( slice_angle[1][i]<MOD_2PI(pie_3D_rad+3.0*M_PI_2) && slice_angle[2][i]>MOD_2PI(pie_3D_rad+3.0*M_PI_2) )
					{
					tmp_slice[num_slice_angles].i       = i;
					tmp_slice[num_slice_angles].hidden  = FALSE;
					tmp_slice[num_slice_angles].slice   = slice_angle[0][i];
					tmp_slice[num_slice_angles++].angle = MOD_2PI( pie_3D_rad+3.0*M_PI_2 );
					}
				}

		qsort( tmp_slice, num_slice_angles, sizeof(struct tmp_slice_t), ocmpr );
		for( t=0; t<num_slice_angles; ++t )
			{
			gdPoint	gdp[4];

			i = tmp_slice[t].i;

			gdp[0].x  = CX(i,0);					gdp[0].y = CY(i,0);
			gdp[1].x  = CX(i,1);					gdp[1].y = CY(i,1);
			gdp[2].x  = OX(i,tmp_slice[t].angle,1);	gdp[2].y = OY(i,tmp_slice[t].angle,1);
			gdp[3].x  = OX(i,tmp_slice[t].angle,0);	gdp[3].y = OY(i,tmp_slice[t].angle,0);

			if( !(tmp_slice[t].hidden) )
				gdImageFilledPolygon( im, gdp, 4, SliceColorShd[i] );
			else
				{
				rad -= 2.0;										/* no peeking */
				gdp[0].x  = OX(i,slice_angle[0][i],0);	gdp[0].y = OY(i,slice_angle[0][i],0);
				gdp[1].x  = OX(i,slice_angle[0][i],1);	gdp[1].y = OY(i,slice_angle[0][i],1);
				rad += 2.0;
				gdp[2].x  = OX(i,slice_angle[1][i],1);	gdp[2].y = OY(i,slice_angle[1][i],1);
				gdp[3].x  = OX(i,slice_angle[1][i],0);	gdp[3].y = OY(i,slice_angle[1][i],0);
				gdImageFilledPolygon( im, gdp, 4, SliceColorShd[i] );
				gdp[2].x  = OX(i,slice_angle[2][i],1);	gdp[2].y = OY(i,slice_angle[2][i],1);
				gdp[3].x  = OX(i,slice_angle[2][i],0);	gdp[3].y = OY(i,slice_angle[2][i],0);
				gdImageFilledPolygon( im, gdp, 4, SliceColorShd[i] );
				}
				

			if( GDCPIE_EdgeColor != GDC_NOCOLOR )
				{
				gdImageLine( im, CX(i,0), CY(i,0), CX(i,1), CY(i,1), EdgeColorShd );
				gdImageLine( im, OX(i,tmp_slice[t].angle,0), OY(i,tmp_slice[t].angle,0),
								 OX(i,tmp_slice[t].angle,1), OY(i,tmp_slice[t].angle,1),
								 EdgeColorShd );
				}
			}
		FREE_ARRAY1( tmp_slice );
		}
		}


	/* ----- pie face ----- */
	{
	/* float	last = 0.0; */
	float	rad1 = rad * 3.0/4.0;
	for( i=0; i<num_points; ++i )
		if( !others[i] &&
			(!GDCPIE_missing || !GDCPIE_missing[i]) )
			{
			int		edge_color = GDCPIE_EdgeColor == GDC_NOCOLOR? SliceColor[i]:
																  EdgeColorShd;
			/* last += val[i]; */
			/* EXPLODE_CX_CY( slice_angle[0][i], i ); */
			gdImageLine( im, CX(i,0), CY(i,0), IX(i,1,0), IY(i,1,0), edge_color );
			gdImageLine( im, CX(i,0), CY(i,0), IX(i,2,0), IY(i,2,0), edge_color );
			gdImageArc( im, CX(i,0), CY(i,0), 
							(int)(rad*ellipsex*2.0), (int)(rad*ellipsey*2.0),
							(TO_INT_DEG_FLOOR(slice_angle[1][i])+270)%360,
							(TO_INT_DEG_CEIL(slice_angle[2][i])+270)%360,
							edge_color );
			/* antialiasing here */
			/* likely only on the face? */
/* bugs in gd2.0.0 */
/*	arc doesn't honor deg>360 */
/*	arcs from gdImageFilledArc() don't match with gdImageArc() */
/*	angles are off */
/*	doesn't always fill completely */
/*			gdImageFilledArc( im, CX(i,0), CY(i,0),  */
/*								  (int)(rad*ellipsex*2.0), (int)(rad*ellipsey*2.0), */
/*								  (TO_INT_DEG_FLOOR(slice_angle[1][i])+270)%360, */
/*								  (TO_INT_DEG_CEIL(slice_angle[2][i])+270)%360, */
/*								  SliceColor[i], */
/*								  gdPie ); */
			/* attempt to fill, if slice is wide enough */
			{
			float	rad = rad1;										/* local override */
			if( (ABS(IX(i,1,1)-IX(i,2,1)) + ABS(IY(i,1,1)-IY(i,2,1))) > 2 )
				{
				gdImageFillToBorder( im, IX(i,0,0), IY(i,0,0), edge_color, SliceColor[i] );
				}
			/* catch missed pixels on narrow slices */
			gdImageLine( im, CX(i,0), CY(i,0), IX(i,0,0), IY(i,0,0), SliceColor[i] );
			}
			}
	}

	if( GDCPIE_title )
		{
		struct fnt_sz_t	tftsz      = GDCfnt_sz( GDCPIE_title,
												GDCPIE_title_size,
												gdcpie_title_font, gdcpie_title_ptsize, 0.0, NULL );
		GDCImageStringNL( im,
						  &GDC_fontc[GDCPIE_title_size],
						  gdcpie_title_font, gdcpie_title_ptsize,
						  0.0,
						  IMGWIDTH/2 - tftsz.w/2,
						  1,
						  GDCPIE_title,
						  LineColor,
						  GDC_JUSTIFY_CENTER,
						  NULL );
		}

	/* labels */
	if( lbl )
		{
		float	liner = rad;

		rad += GDCPIE_label_dist;
		for( i=0; i<num_points; ++i )
			{
			if( !others[i] &&
				(!GDCPIE_missing || !GDCPIE_missing[i]) )
				{
				int		lblx,  pctx,
						lbly,  pcty,
						linex, liney;

				lbly = (liney = IY(i,0,0))-lbl_ftsz[i].h / 2;
				lblx = pctx = linex = IX(i,0,0);

				if( slice_angle[0][i] > M_PI )								/* which semicircle */
					{
					lblx -= lbl_ftsz[i].w;
					pctx = lblx;
					++linex;
					}
				else
					--linex;

				switch( GDCPIE_percent_labels )
					{
					case GDCPIE_PCT_LEFT:	if( slice_angle[0][i] > M_PI )
												pctx -= lbl_ftsz[i].w-1;
											else
												lblx += pct_ftsz[i].w+1;
											pcty = IY(i,0,0) - ( 1+pct_ftsz[i].h ) / 2;
											break;
					case GDCPIE_PCT_RIGHT:	if( slice_angle[0][i] > M_PI )
												lblx -= pct_ftsz[i].w-1;
											else
												pctx += lbl_ftsz[i].w+1;
											pcty = IY(i,0,0) - ( 1+pct_ftsz[i].h ) / 2;
											break;
					case GDCPIE_PCT_ABOVE:	lbly += (1+pct_ftsz[i].h) / 2;
											pcty = lbly - pct_ftsz[i].h;
											break;
					case GDCPIE_PCT_BELOW:	lbly -= (1+pct_ftsz[i].h) / 2;
											pcty = lbly + lbl_ftsz[i].h;
											break;
					case GDCPIE_PCT_NONE:
					default:;
					}

				if( GDCPIE_percent_labels != GDCPIE_PCT_NONE )
					GDCImageStringNL( im,
									  &GDC_fontc[GDCPIE_label_size],
									  gdcpie_label_font, gdcpie_label_ptsize,
									  0.0,
									  slice_angle[0][i] <= M_PI? pctx:
																 pctx+lbl_ftsz[i].w-pct_ftsz[i].w,
									  pcty,
									  pct_lbl[i],
									  LineColor,
									  GDC_JUSTIFY_CENTER,
									  NULL );
				if( lbl[i] )
					GDCImageStringNL( im,
									  &GDC_fontc[GDCPIE_label_size],
									  gdcpie_label_font, gdcpie_label_ptsize,
									  0.0,
									  lblx,
									  lbly,
									  lbl[i],
									  LineColor,
									  slice_angle[0][i] <= M_PI? GDC_JUSTIFY_LEFT:
																 GDC_JUSTIFY_RIGHT,
									  NULL );
				if( GDCPIE_label_line )
					{
					float	rad = liner;
					gdImageLine( im, linex, liney, IX(i,0,0), IY(i,0,0), LineColor );
					}
				}
			}
		rad -= GDCPIE_label_dist;
		}

		fflush( img_fptr );
		switch( GDC_image_type )
			{
#ifdef HAVE_JPEG
			case GDC_JPEG:	gdImageJpeg( im, img_fptr, GDC_jpeg_quality );	break;
#endif
			case GDC_WBMP:	gdImageWBMP( im, PlotColor, img_fptr );			break;
			case GDC_GIF:	gdImageGif( im, img_fptr);						break;
			case GDC_PNG:
			default:		gdImagePng( im, img_fptr );
			}

	FREE_ARRAY1( lbl_ftsz );
	FREE_ARRAY1( pct_ftsz );
	FREE_ARRAY2( pct_lbl );

	FREE_ARRAY2( slice_angle );
	FREE_ARRAY1( others );

	FREE_ARRAY1( SliceColorShd );
	FREE_ARRAY1( SliceColor );
	gdImageDestroy(im);
	return;
}