/** 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); } }
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; }
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)); }
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; }
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"); }
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; }
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))); }
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); }
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; }
/* ======================================================= *\ * 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; }