static double compute_distance(double lon1, double lat1, double lon2, double lat2) /* Compute the great circle distance between two point on the earth's surface in degrees. Both the input and the output values are in degrees. Returns a number between 0 and 180 */ { lon1 = to_radians(lon1); lat1 = to_radians(lat1); lon2 = to_radians(lon2); lat2 = to_radians(lat2); double sin_lat1 = sin(lat1); double cos_lat1 = cos(lat1); double sin_lat2 = sin(lat2); double cos_lat2 = cos(lat2); double delta_lon = lon2 - lon1; double cos_delta_lon = cos(delta_lon); double sin_delta_lon = sin(delta_lon); double angle = atan2(sqrt(square(cos_lat2 * sin_delta_lon) + square(cos_lat1 * sin_lat2 - sin_lat1 * cos_lat2 * cos_delta_lon)), sin_lat1 * sin_lat2 + cos_lat1 * cos_lat2 * cos_delta_lon); return to_degrees(angle); }
static void invert_dist_azimuth(double lon1, double lat1, double dist, double azi, double * out_lon2, double * out_lat2) /* Return the location loc2=(longitude, latitude) such that compute_distance(loc1, loc2) == dist and compute_azimuth(loc1, loc2) = azi. Or, in other words if we move along the great-circle from 'loc1' along the azimuth 'azi' for a distance of 'dist' degrees then we will reach loc2. Example: invert_dist_azimuth(10, 0, 10.049369393181079, 95.740074136412659, ..) --> 20, 0 */ { /* convert everything to radians */ lon1 = to_radians(lon1); lat1 = to_radians(lat1); dist = to_radians(dist); azi = to_radians(azi); double lat2 = asin(sin(lat1) * cos(dist) + cos(lat1) * sin(dist) * cos(azi)); double lon2 = lon1 + atan2(sin(azi) * sin(dist) * cos(lat1), cos(dist) - sin(lat1) * sin(lat2)); *out_lon2 = to_degrees(lon2); *out_lat2 = to_degrees(lat2); }
Line* Triangle::rotate_vector(Line* vector, Point* center,float angle) { static Point *anchor = new Point(); anchor->x = vector->a->x; anchor->y = vector->a->y; vector->b->x -= anchor->x;//0 vector->b->y -= anchor->y;//0 vector->a->x -= anchor->x; vector->a->y -= anchor->y; float vx = vector->b->x; float vy = vector->b->y; vector->b->x = (vx*cos(to_radians(angle)) - vy*sin(to_radians(angle))); vector->b->y = (vx*sin(to_radians(angle)) + vy*cos(to_radians(angle))); //need if rotate around center // vx = vector->a->x; // vy = vector->a->y; // vector->a->x = (vx*cos(to_radians(angle)) - vy*sin(to_radians(angle))); // vector->a->y = (vx*sin(to_radians(angle)) + vy*cos(to_radians(angle))); vector->b->x += anchor->x; vector->b->y += anchor->y; vector->a->x += anchor->x; vector->a->y += anchor->y; return vector; }
Point* Triangle::rotate_point(Point* p, Point* anchor, float angle) { float vx = 0; //can be changed to rotate entire rectangle float vy = Triangle::EGDE_LENGTH; //p->x can be mult by -1 to change pivot point of rotate p->x = -(vx*cos(to_radians(angle)) - vy*sin(to_radians(angle))); p->y = vx*sin(to_radians(angle)) + vy*cos(to_radians(angle)); p->x += anchor->x; p->y += anchor->y; // p->draw(); return p; }
double distance(city* from, city* to) { double f_lat_rad = to_radians(from->latitude); double t_lat_rad = to_radians(to->latitude); double f_lon_rad = to_radians(from->longitude); double t_lon_rad = to_radians(to->longitude); double diff_lat = fabs(t_lat_rad - f_lat_rad); double diff_lon = fabs(t_lon_rad - f_lon_rad); double a = sin(diff_lat/2)*sin(diff_lat/2) + (cos(f_lat_rad)*cos(t_lat_rad)*sin(diff_lon/2)*sin(diff_lon/2)); double c = 2*atan2(sqrt(a), sqrt(1-a)); return c*EARTH_RADIUS; }
void OpenSpace::initialize() { maxProgress(200); setAllEdges(false); world().SetGravity(b2Vec2(0, 10)); upper = makePlatform(10, -25); addProgress(25); middle = makePlatform(50, -25); addProgress(25); auto pd = physicsDimensions(); for(int i = 0; i < 150; ++i) { polygonDef def; def.bodyDef.position.Set(randuniform(pd.x, pd.x + 30), randuniform(-30, pd.y-30)); def.bodyDef.angle = to_radians(randuniform(0, 360)); def.bodyDef.type = b2_dynamicBody; def.shape.SetAsBox(1, 5); def.fixtureDef.restitution = 0.5; def.fixtureDef.density = 4; bodies.push_back(make_shape(world(), def)); addProgress(1); } }
int L_tan(lua_State * env) { float x = lua_tointeger(env, -1); float result = to_degrees(tan(to_radians(x))); lua_pushnumber(env, result); return 1; }
Area Ship::bounding() const { // the idea in the following code is to calculate a bounding box // around the ship's triangle and use it for collision detection. // TODO: find a nicer way of rotating and translating // (-center_ and +center_ is not intuitive) // first calculate the triangle 'shadowing' the triangle on display // this means a rotation and translation needs to be applied to the // known points (see Ship::draw for comparison to the OpenGL code) const vector2 &RA = A_ - center_, &RB = B_ - center_, &RC = C_ - center_; // this is probably inefficient vector2 RRA(0, 0), RRB(0, 0), RRC(0, 0); float ra = to_radians(rot_angle_); rotate_vector(RA, ra, RRA); rotate_vector(RB, ra, RRB); rotate_vector(RC, ra, RRC); RRA += pos_ + center_; RRB += pos_ + center_; RRC += pos_ + center_; const vector2* points[3] = { &RRA, &RRB, &RRC } ; // no point storing the bounding box, because it depends on position // find a bounding box encompassing all points return Area::minimumArea(points, 3); }
float8 colors_delta_e_cmc(float8 l1, float8 a1, float8 b1, float8 l2, float8 a2, float8 b2, float8 pl, float8 pc) { float8 C_1, C_2, delta_L, delta_C, H_1, F, T, S_L, S_C, S_H, delta_H_sq, delta_H; C_1 = sqrt(pow(a1, 2) + pow(b1, 2)); C_2 = sqrt(pow(a2, 2) + pow(b2, 2)); delta_L = l1 - l2; delta_C = C_1 - C_2; H_1 = to_degrees(atan2(b1, a1)); H_1 += (H_1 < 0 ? 360 : 0); F = sqrt(pow(C_1, 4) / (pow(C_1, 4) + 1900.0)); if (164 <= H_1 && H_1 <= 345) { T = 0.56 + fabs(0.2 * cos(to_radians(H_1 + 168))); } else { T = 0.36 + fabs(0.4 * cos(to_radians(H_1 + 35))); } if (l1 < 16) { S_L = 0.511; } else { S_L = (0.040975 * l1) / (1 + 0.01765 * l1); } S_C = ((0.0638 * C_1) / (1 + 0.0131 * C_1)) + 0.638; S_H = S_C * (F * T + 1 - F); delta_H_sq = -pow(delta_C, 2) + pow(a1 - a2, 2) + pow(b1 - b2, 2); delta_H = sqrt((delta_H_sq > 0 ? delta_H_sq : 0)); return sqrt(pow(delta_L / (pl * S_L), 2) + pow(delta_C / (pc * S_C), 2) + pow(delta_H / S_H, 2)); }
void set_primitive_angle(PRIMITIVE *p, float angle) { float offset_angle; int i; if (p == NULL) return; offset_angle = angle - p->angle; p->angle = angle; p->velocity.x = p->speed * cosf(to_radians(angle)); p->velocity.y = p->speed * sinf(to_radians(angle)); for (i=0; i<p->size; i++) { point2_rotate(&p->points[i], to_radians(offset_angle), p->centroid.x, p->centroid.y); } }
void move_line(FPOINT *point1, FPOINT *point2, FPOINT *centroid, VECTOR2D velocity, float rotation) { FPOINT orig_centroid = *centroid; float offset_x, offset_y; if (point1 == NULL || point2 == NULL) return; centroid->x += velocity.x; centroid->y += velocity.y; offset_x = centroid->x - orig_centroid.x; offset_y = centroid->y - orig_centroid.y; point1->x += offset_x; point1->y += offset_y; point2->x += offset_x; point2->y += offset_y; point2_rotate(point1, to_radians(rotation), centroid->x, centroid->y); point2_rotate(point2, to_radians(rotation), centroid->x, centroid->y); }
void D_ShotObj::DrawShot() { RotationAngleZ = Angle + 90; D3DXMatrixAffineTransformation2D(&Transform, Scale, nullptr,to_radians(RotationAngleZ), &OFFSET); SpriteBatch->SetTransform(&Transform); SpriteBatch->Draw(Texture, &SourceRect, &D3DXVECTOR3(Origin.x, Origin.y, 0), nullptr, D3DCOLOR_ARGB(255, 255, 255, 255)); }
static dynamixel_device_status_t* axseries_get_status(dynamixel_device_t *device) { dynamixel_msg_t *msg = dynamixel_msg_create(2); msg->buf[0] = 0x24; msg->buf[1] = 8; dynamixel_msg_t *resp = device->bus->send_command(device->bus, device->id, INST_READ_DATA, msg, 1); dynamixel_msg_destroy(msg); if (resp == NULL) return NULL; dynamixel_device_status_t *stat = dynamixel_device_status_create(); stat->position_radians = ((resp->buf[1] & 0xff) + ((resp->buf[2] & 0x3) << 8)) * to_radians(300) / 1024.0 - to_radians(150); int tmp = ((resp->buf[3] & 0xff) + ((resp->buf[4] & 0x3f) << 8)); if (tmp < 1024) stat->speed = tmp / 1023.0; else stat->speed = -(tmp - 1024)/1023.0; // load is signed, we scale to [-1, 1] tmp = (resp->buf[5] & 0xff) + ((resp->buf[6] & 0xff) << 8); if (tmp < 1024) stat->load = tmp / 1023.0; else stat->load = -(tmp - 1024) / 1023.0; stat->voltage = (resp->buf[7] & 0xff) / 10.0; // scale to voltage stat->temperature = (resp->buf[7] & 0xff); // deg celcius stat->continuous = device->rotation_mode; stat->error_flags = (resp->buf[0] & 0xff); return stat; }
b2Body* OpenSpace::makePlatform(float ycenter, float angle) { auto pd = physicsDimensions(); polygonDef def; def.bodyDef.position.Set(pd.x, ycenter); def.bodyDef.type = b2_staticBody; def.bodyDef.angle = to_radians(angle); def.bodyDef.fixedRotation = true; def.shape.SetAsBox(pd.x-40, 2); def.fixtureDef.density = 1; def.fixtureDef.friction = 0.4; return make_shape(world(), def); }
VEC2 *rotate2(VEC2 *vec, float angle) { float rad; float c; float s; rad = to_radians(angle); c = cos(rad); s = sin(rad); vec->x = vec->x * c - vec->y * s; vec->y = vec->x * s + vec->y * c; return (vec); }
static double compute_azimuth(double lon1, double lat1, double lon2, double lat2) /* Angle in degrees measured clockwise from north starting at loc1 towards loc2. loc1 and loc2 are (longitude, latitude) in degrees. See https://en.wikipedia.org/wiki/Great-circle_navigation. However, we want north = 0 degrees, east = 90 degrees, south = 180 degrees, and west = 270 degrees. Return an angle in 0 to 360 degrees. */ { lon1 = to_radians(lon1); lat1 = to_radians(lat1); lon2 = to_radians(lon2); lat2 = to_radians(lat2); double delta_lon = lon2 - lon1; double y = sin(delta_lon); double x = cos(lat1) * tan(lat2) - sin(lat1) * cos(delta_lon); double azi = to_degrees(atan2(y, x)); /* azi is now in range -180/180 the following trick brings it in the 0 - 360 range */ return fmod(azi + 360 , 360); }
void TreeSystem::make_ground( float thickness, float base_angle, float delta_angle, const sf::Color& base_color, const ColorTransform& deltas) { const float density_factor = 1.5; const float block_w = 5; const float block_h = 1; const float block_area = block_w * block_h; const float underground_depth = 5; auto phys = physicsDimensions(); auto phys2 = physicsHalfDimensions(); const float area = (thickness + underground_depth) * phys.x; const unsigned density = (area * density_factor) / block_area; blocks.reserve(blocks.size() + density + 1); polygonDef def; def.bodyDef.active = false; def.bodyDef.fixedRotation = true; def.bodyDef.type = b2_staticBody; def.shape.SetAsBox(phys2.x, thickness/2); def.bodyDef.angle = 0; def.bodyDef.position.Set(phys2.x, phys.y - (thickness/2)); blocks.emplace_back( make_shape(world(), def), base_color); def.shape.SetAsBox(block_w, block_h); addProgress(1); const b2Vec2 topLeft(0, phys.y - thickness); const b2Vec2 bottomRight(phys.x, phys.y + underground_depth); maxProgress(blocks.size() + density + 1); setProgress(blocks.size()); for(int i = 0; i < density; ++i) { def.bodyDef.position = random_in(topLeft, bottomRight); def.bodyDef.angle = to_radians(randcentered(base_angle, delta_angle)); add_block(def, deltas.apply(base_color)); addProgress(1); } }
void move_polygon(FPOINT *points, int size, FPOINT *centroid, VECTOR2D velocity, float *angle, float rotation, FRECT *bounding_box) { FPOINT orig_centroid = *centroid; float offset_x, offset_y; float min_x, max_x, min_y, max_y; int p; centroid->x += velocity.x; centroid->y += velocity.y; offset_x = centroid->x - orig_centroid.x; offset_y = centroid->y - orig_centroid.y; if (angle != NULL) *angle = wrapf(*angle + rotation, FULL_DEG); if (points != NULL && size > 0) { max_x = min_x = centroid->x; max_y = min_y = centroid->y; for (p=0; p<size; p++) { points[p].x += offset_x; points[p].y += offset_y; point2_rotate(&points[p], to_radians(rotation), centroid->x, centroid->y); if (bounding_box != NULL) { if (points[p].x < min_x) min_x = points[p].x; else if (points[p].x > max_x) max_x = points[p].x; if (points[p].y < min_y) min_y = points[p].y; else if (points[p].y > max_y) max_y = points[p].y; } } if (bounding_box != NULL) { bounding_box->x = min_x; bounding_box->w = max_x - min_x; bounding_box->y = min_y; bounding_box->h = max_y - min_y; } } }
std::pair<double, double> georeference_target_in_image(int targetrow, int targetcol, int imrows, int imcols, double planelat, double planelongt, double planeheading, double planealtitude) { double pxperfeet = static_calculate_px_per_feet(imcols, planealtitude, 1.0); //default scalefactor: 1.0 planeheading = planeheading - kPI; //Gimbal is reversed in plane double rowdiff = targetrow - (double)imrows/2; //row diff from center (and center of plane) double coldiff = targetcol - (double)imcols/2; //col diff from center (and center of plane) // Tranlate to polar coordinates, in feet double centerdiff = sqrt(pow(rowdiff, 2) + pow(coldiff, 2)); double centerfeetdiff = centerdiff / pxperfeet; double centerangle = atan2(coldiff, rowdiff); //clockwise from up (we use coordinate system North-Is-Up == 0 degrees, East-Is-Right == 90 degrees) //the image may not be facing up==north, so planeheading is used as the offset //atan2(x,y) is clockwise from up //atan2(y,x) is counterclockwise from right (ordinary polar coordinates) // Project to Lat/Long; convert planeheading from degrees to radians double latfeetdiff = centerfeetdiff * cos(planeheading*0.01745329251994329577 + centerangle); double longtfeetdiff = centerfeetdiff * sin(planeheading*0.01745329251994329577 + centerangle); // Convert Lat/Long feet differences into degrees to get final lat/long double target_lat = planelat + latfeetdiff/365221.43; //365221 feet in 1 degree of latitude arc, small angle assumptions for field; double longt_deg_to_feet = kPI * 20898855.01138578 * cos(to_radians(target_lat)) / 180; //Radius of circle at this lat, (PI*R)/(180) double target_longt = planelongt + longtfeetdiff/longt_deg_to_feet; //cout << "heading: " << planeheading << endl; //cout << "imrows: " << imrows << " imcols: " << imcols << endl; //cout << "rd: " << rowdiff << endl; //cout << "cd: " << coldiff << endl; //cout << "ppf: " << pxperfeet << endl; //cout << "centerdiff: " << centerdiff << endl; //cout << "centerfeetdiff: " << centerfeetdiff << endl; //cout << "centerangle: " << centerangle << endl; //printf("lat diff: %.7f\tdeg, %.3f feet\n", latfeetdiff/365221, latfeetdiff); //printf("long diff: %.7f\tdeg, %.3f feet\n", longtfeetdiff/longt_deg_to_feet, longtfeetdiff); return std::pair<double, double>(target_lat, target_longt); }
void OVR_SDL2_nav::step() { mat3 N = normal(inverse(yrotation(to_radians(rotation)))); vec3 v = dposition; if (move_L) v = v + vec3(-1, 0, 0); if (move_R) v = v + vec3(+1, 0, 0); if (move_D) v = v + vec3(0, -1, 0); if (move_U) v = v + vec3(0, +1, 0); if (move_F) v = v + vec3(0, 0, -1); if (move_B) v = v + vec3(0, 0, +1); if (length(v) > 1.0) v = normalize(v); position = position + N * v / 30.0; rotation = rotation + drotation; }
/// /// \brief "Fires" a round from the Ship's ammo collection. The count of /// ammo is decremented thereafter. /// \return void /// void Ship::fire() { if (ammo_pos_ != ammo_.end()) { vector2 bP(0, 0); // calculate the position of the bullet at the 'nose' of the ship float ra = to_radians(rot_angle_); rotate_vector((C_ - center_), ra, bP); bP += pos_ + center_; (*ammo_pos_).fire(bP, vel_ * 5); ++ammo_pos_; } else { DEBUG_PRINT << ">>> OUT OF AMMO -- RELOADING!" << std::endl; reloadAmmo(); } }
void Flat::initialize() { const int num_things = 75; maxProgress(num_things * 3); for(int i = 0; i < num_things; ++i) { polygonDef def; def.bodyDef.position.Set(randuniform(50, 100), randuniform(0, 80)); def.bodyDef.angle = 0; def.bodyDef.fixedRotation = true; def.bodyDef.type = b2_dynamicBody; def.shape.SetAsBox(1*1.2, 5*1.2); def.fixtureDef.density = 1; (make_shape(back1, def)); addProgress(1); } for(int i = 0; i < num_things; ++i) { polygonDef def; def.bodyDef.position.Set(randuniform(50, 100), randuniform(0, 80)); def.bodyDef.angle = to_radians(randuniform(0, 360)); def.bodyDef.type = b2_dynamicBody; def.shape.SetAsBox(1, 5); def.fixtureDef.density = 1; (make_shape(back2, def)); addProgress(1); } for(int i = 0; i < num_things; ++i) { polygonDef def; def.bodyDef.position.Set(randuniform(50, 100), randuniform(0, 80)); def.bodyDef.angle = 0; def.bodyDef.fixedRotation = true; def.bodyDef.type = b2_dynamicBody; def.shape.SetAsBox(1*0.8, 5*0.8); def.fixtureDef.density = 1; (make_shape(back3, def)); addProgress(1); } }
void Ship::rotateVelocity() { // // // C // * // *|* // * | * // * | * // * | * // A * * * * * * B // M // // M_C = C - M // // M is the mid-point between A and B // // The idea is to calculate the direction by calculating the // vector M_C and rotating it // // ^ // ^ // ^ // C // *^* // * ^ * // * ^ * // A * * * * * B // // const vector2 M((A_[0] + B_[0]) / 2, (A_[1] + B_[1]) / 2), M_C = (C_ - M).normalize(); // use a 2D rotation matrix to rotate the M_C vector, so the ship // goes 'forwards' with C as the front of the ship, rather than // at some weird angle rotate_vector(M_C, to_radians(rot_angle_), vel_); vel_ *= speed_; }
bool wrl::constraint::point(const vec3& p, const vec3& v, mat4& A) { if (to_degrees(acos(mouse_v * v)) > 1.0) { if (mode) { double a; double d; calc_rot(a, d, p, v); if (fabs(a - mouse_a) > 0.0 || fabs(d - mouse_d) > 0.0) { A = translation( wvector(T)) * rotation( zvector(T), to_radians(a - mouse_a)) * translation(-wvector(T)); return true; } } else { double x; double y; calc_pos(x, y, p, v); if (fabs(x - mouse_x) > 0.0 || fabs(y - mouse_y) > 0.0) { A = translation(xvector(T) * (x - mouse_x) + yvector(T) * (y - mouse_y)); return true; } } } return false; }
void TreeSystem::make_tree( int iterations, b2Vec2 base, float ratio1, float ratio2, float min_core_angle, float max_core_angle, float min_branch_angle_1, float max_branch_angle_1, float min_branch_angle_2, float max_branch_angle_2, float initial_size, float leaf_size, const sf::Color& bark, const ColorTransform& bark_trans, const std::vector<LeafSystem>& over_leaves, const std::vector<LeafSystem>& under_leaves) { TreeNode::ratio1 = ratio1; TreeNode::ratio2 = ratio2; TreeNode::min_ca = min_core_angle; TreeNode::max_ca = max_core_angle; TreeNode::min_ba1 = min_branch_angle_1; TreeNode::max_ba1 = max_branch_angle_1; TreeNode::min_ba2 = min_branch_angle_2; TreeNode::max_ba2 = max_branch_angle_2; //Generate Tree std::list<TreeNode> grown; std::list<TreeNode> growing; std::list<TreeNode> upcoming; grown.emplace_back(base, initial_size); growing.emplace_back(grown.back(), true); for(unsigned i = 0; i < iterations; ++i) { for(TreeNode& node: growing) { upcoming.emplace_back(node, true); upcoming.emplace_back(node, false); } grown.splice(grown.end(), growing); growing.splice(growing.end(), upcoming); } grown.splice(grown.end(), growing); auto make_leaves = [&](const std::vector<LeafSystem>& leaves)->void { polygonDef leafDef; leafDef.bodyDef.active = false; leafDef.bodyDef.type = b2_staticBody; leafDef.bodyDef.fixedRotation = true; for(const LeafSystem& system : leaves) { leafDef.shape.SetAsBox(5 * system.size, system.size); for(const TreeNode& node : grown) { if(system.min_depth > node.get_id() && system.min_depth >= 0) continue; if(system.max_depth < node.get_id() && system.max_depth >= 0) break; const float length = node.get_length(); float num_leaves = (length * length * system.density / 2.5); if(system.density < 0 || (num_leaves < 1 && randuniform(0, 1) < num_leaves)) num_leaves = 1.5; const unsigned count_leaves = num_leaves; const auto center = node.center(); for(unsigned i = 0; i < count_leaves; ++i) { leafDef.bodyDef.position = random_centered(center, system.density < 0 ? 0 : length / 2); leafDef.bodyDef.angle = to_radians(randcentered(system.base_dangle, system.delta_dangle)); add_block(leafDef, system.transform.apply(system.color)); } } } }; make_leaves(under_leaves); polygonDef def; def.bodyDef.active = false; def.bodyDef.fixedRotation = true; def.bodyDef.type = b2_staticBody; for(TreeNode& node : grown) { def.bodyDef.position = node.center(); def.bodyDef.angle = -node.get_angle(); def.shape.SetAsBox(node.get_length() / 2, node.get_length() / 10); add_block(def, bark_trans.apply(bark)); } make_leaves(over_leaves); }
static double axseries_get_max_position_radians() { return to_radians(150); }
float4x4 get_view_proj_matrix() { auto p = look_at_pose(position, position + direction); return mul(make_perspective_matrix(to_radians(cutoff * 2.0f), 1.0f, 0.1f, 1000.f), make_view_matrix_from_pose(p)); }
float get_cutoff() { return cosf(to_radians(cutoff)); }
void set_dimensions(float l, float a) { angle = (parent ? parent->angle : 0) + (to_radians(a) * (inverse ? - 1 : 1)); set_length(l); }
float8 colors_delta_e_cie_2000(float8 l1, float8 a1, float8 b1, float8 l2, float8 a2, float8 b2, float8 Kl, float8 Kc, float8 Kh) { float8 avg_Lp, C1, C2, avg_C1_C2, G, a1p, a2p, C1p, C2p, avg_C1p_C2p, h1p, h2p, avg_Hp, T, diff_h2p_h1p, delta_hp, delta_Lp, delta_Cp, delta_Hp, S_L, S_C, S_H, delta_ro, R_C, R_T; avg_Lp = (l1+l2)/2.0; C1 = sqrt(pow(a1, 2.0) + pow(b1, 2.0)); C2 = sqrt(pow(a2, 2.0) + pow(b2, 2.0)); avg_C1_C2 = (C1 + C2) / 2.0; G = 0.5 * (1 - sqrt(pow(avg_C1_C2, 7.0) / (pow(avg_C1_C2, 7.0) + pow(25.0, 7.0)))); a1p = (1.0 + G) * a1; a2p = (1.0 + G) * a2; C1p = sqrt(pow(a1p, 2.0) + pow(b1, 2.0)); C2p = sqrt(pow(a2p, 2.0) + pow(b2, 2.0)); avg_C1p_C2p = (C1p + C2p) / 2.0; h1p = to_degrees(atan2(b1, a1p)); h1p += (h1p < 0 ? 360 : 0); h2p = to_degrees(atan2(b2, a2p)); h2p += (h2p < 0 ? 360 : 0); avg_Hp = ((fabs(h1p - h2p) > 180 ? 360 : 0) + h1p + h2p) / 2.0; T = 1 - 0.17 * cos(to_radians(avg_Hp - 30)) + 0.24 * cos(to_radians(2 * avg_Hp)) + 0.32 * cos(to_radians(3 * avg_Hp + 6)) - 0.2 * cos(to_radians(4 * avg_Hp - 63)); diff_h2p_h1p = h2p - h1p; delta_hp = diff_h2p_h1p + (fabs(diff_h2p_h1p) > 180 ? 360 : 0); delta_hp -= (h2p > h1p ? 720 : 0); delta_Lp = l2 - l1; delta_Cp = C2p - C1p; delta_Hp = 2 * sqrt(C2p * C1p) * sin(to_radians(delta_hp) / 2.0); S_L = 1 + ((0.015 * pow(avg_Lp - 50, 2.0)) / sqrt(20 + pow(avg_Lp - 50, 2.0))); S_C = 1 + 0.045 * avg_C1p_C2p; S_H = 1 + 0.015 * avg_C1p_C2p * T; delta_ro = 30 * exp(-(pow(((avg_Hp - 275) / 25), 2.0))); R_C = sqrt((pow(avg_C1p_C2p, 7.0)) / (pow(avg_C1p_C2p, 7.0) + pow(25.0, 7.0))); R_T = -2 * R_C * sin(2 * to_radians(delta_ro)); return sqrt( pow(delta_Lp / (S_L * Kl), 2) + pow(delta_Cp / (S_C * Kc), 2) + pow(delta_Hp / (S_H * Kh), 2) + R_T * (delta_Cp / (S_C * Kc)) * (delta_Hp / (S_H * Kh))); }