I need to calculate Tanh-1 in C#
(and Sinh-1 and Cosh-1)
I did not found it in Math library.. Any suggestions ?
EDIT:
Tanh not Tan !!
You need to derive them yourself using existing functions e.g. Math.sin
You might find this useful:
Secant Sec(X) = 1 / Cos(X)
Cosecant Cosec(X) = 1 / Sin(X)
Cotangent Cotan(X) = 1 / Tan(X)
Inverse Sine Arcsin(X) = Atn(X / Sqr(-X * X + 1))
Inverse Cosine Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
Inverse Secant Arcsec(X) = 2 * Atn(1) - Atn(Sgn(X) / Sqr(X * X - 1))
Inverse Cosecant Arccosec(X) = Atn(Sgn(X) / Sqr(X * X - 1))
Inverse Cotangent Arccotan(X) = 2 * Atn(1) - Atn(X)
Hyperbolic Sine HSin(X) = (Exp(X) - Exp(-X)) / 2
Hyperbolic Cosine HCos(X) = (Exp(X) + Exp(-X)) / 2
Hyperbolic Tangent HTan(X) = (Exp(X) - Exp(-X)) / (Exp(X) + Exp(-X))
Hyperbolic Secant HSec(X) = 2 / (Exp(X) + Exp(-X))
Hyperbolic Cosecant HCosec(X) = 2 / (Exp(X) - Exp(-X))
Hyperbolic Cotangent HCotan(X) = (Exp(X) + Exp(-X)) / (Exp(X) - Exp(-X))
Inverse Hyperbolic Sine HArcsin(X) = Log(X + Sqr(X * X + 1))
Inverse Hyperbolic Cosine HArccos(X) = Log(X + Sqr(X * X - 1))
Inverse Hyperbolic Tangent HArctan(X) = Log((1 + X) / (1 - X)) / 2
Inverse Hyperbolic Secant HArcsec(X) = Log((Sqr(-X * X + 1) + 1) / X)
Inverse Hyperbolic Cosecant HArccosec(X) = Log((Sgn(X) * Sqr(X * X + 1) + 1) / X)
Inverse Hyperbolic Cotangent HArccotan(X) = Log((X + 1) / (X - 1)) / 2
Logarithm to base N LogN(X) = Log(X) / Log(N)
To .NET-ify David Relihan's formulas:
public static class MathHelper
{
// Secant
public static double Sec(double x)
{
return 1/Math.Cos(x);
}
// Cosecant
public static double Cosec(double x)
{
return 1/Math.Sin(x);
}
// Cotangent
public static double Cotan(double x)
{
return 1/Math.Tan(x);
}
// Inverse Sine
public static double Arcsin(double x)
{
return Math.Atan(x / Math.Sqrt(-x * x + 1));
}
// Inverse Cosine
public static double Arccos(double x)
{
return Math.Atan(-x / Math.Sqrt(-x * x + 1)) + 2 * Math.Atan(1);
}
// Inverse Secant
public static double Arcsec(double x)
{
return 2 * Math.Atan(1) - Math.Atan(Math.Sign(x) / Math.Sqrt(x * x - 1));
}
// Inverse Cosecant
public static double Arccosec(double x)
{
return Math.Atan(Math.Sign(x) / Math.Sqrt(x * x - 1));
}
// Inverse Cotangent
public static double Arccotan(double x)
{
return 2 * Math.Atan(1) - Math.Atan(x);
}
// Hyperbolic Sine
public static double HSin(double x)
{
return (Math.Exp(x) - Math.Exp(-x)) / 2 ;
}
// Hyperbolic Cosine
public static double HCos(double x)
{
return (Math.Exp(x) + Math.Exp(-x)) / 2 ;
}
// Hyperbolic Tangent
public static double HTan(double x)
{
return (Math.Exp(x) - Math.Exp(-x)) / (Math.Exp(x) + Math.Exp(-x));
}
// Hyperbolic Secant
public static double HSec(double x)
{
return 2 / (Math.Exp(x) + Math.Exp(-x));
}
// Hyperbolic Cosecant
public static double HCosec(double x)
{
return 2 / (Math.Exp(x) - Math.Exp(-x));
}
// Hyperbolic Cotangent
public static double HCotan(double x)
{
return (Math.Exp(x) + Math.Exp(-x)) / (Math.Exp(x) - Math.Exp(-x));
}
// Inverse Hyperbolic Sine
public static double HArcsin(double x)
{
return Math.Log(x + Math.Sqrt(x * x + 1)) ;
}
// Inverse Hyperbolic Cosine
public static double HArccos(double x)
{
return Math.Log(x + Math.Sqrt(x * x - 1));
}
// Inverse Hyperbolic Tangent
public static double HArctan(double x)
{
return Math.Log((1 + x) / (1 - x)) / 2 ;
}
// Inverse Hyperbolic Secant
public static double HArcsec(double x)
{
return Math.Log((Math.Sqrt(-x * x + 1) + 1) / x);
}
// Inverse Hyperbolic Cosecant
public static double HArccosec(double x)
{
return Math.Log((Math.Sign(x) * Math.Sqrt(x * x + 1) + 1) / x) ;
}
// Inverse Hyperbolic Cotangent
public static double HArccotan(double x)
{
return Math.Log((x + 1) / (x - 1)) / 2;
}
// Logarithm to base N
public static double LogN(double x, double n)
{
return Math.Log(x) / Math.Log(n);
}
}
You need to define them yourself.
http://en.wikipedia.org/wiki/Hyperbolic_function#Inverse_functions_as_logarithms
-1 1 1 + x
tanh x = — ln —————
2 1 - x
-1 _______
sinh x = ln ( x + √ x² + 1 )
-1 _______
cosh x = ln ( x + √ x² - 1 )
There is also faster formula for computing tanh, requiring only one exp(), because tanh is related to logistic function:
tanh(x) = 2 / (1 + exp(-2 * x)) - 1
also
tanh(x) = 1 - 2 / (1 + exp(2 * x))
See: http://en.wikipedia.org/wiki/Logistic_function
Related
So I'm running iterations with this formula:
double x = 10 / 0.25 * ((0.0002 * x1 * (10 - 0.25 * x1)) + 0.00217 * x2 * (20 - 0.25 * x2)); With this process: Xn+1 = f(Xn).
And if you start from negative X you will eventually end up with (-/+) infinity, so after 6 iterations I'm supposed to get infinity, but what I got surprised me and I couldn't find anywhere what that is, I got "-?", I've tried comparing it to +/- infinity and tried to compare it to int numbers just to clarify what it is, but I cant get anything out of it, for example, I've tried if ("-?" > 1000) break;, and it doesn't outcome as "true". Neither am I getting any errors by comparing it to int/double, I need to stop iterations when I start going into infinity, how can I do that?
code:
public static double CalculateX1(double x1, double x2)
{
double x = 10 / 0.25 * ((0.0002 * x1 * (10 - 0.25 * x1)) + 0.00217 * x2 * (20 - 0.25 * x2));
return x;
}
public static double CalculateX2(double x2, double x1)
{
double y = 20 / 0.25 * ((0.00052 * x2 * (20 - 0.25 * x2)) + 0.0075 * x1 * (10 - 0.25 * x1));
return y;
}
static void Main(string[] args)
{
string writePath = #"C:\Users\evluc\Desktop\cord.txt";
double X = -5;
double Y = -5;
int pointer = 1;
double[,] coordinates = new double[10001, 2];
coordinates[0, 0] = X;
coordinates[0, 1] = Y;
for (int i = 0; i < 5000; i++)
{
//double XTemp = CalculateX1(X, Y);
//double YTemp = CalculateX2(Y, X);
//X = CalculateX1(coordinates[pointer - 1, 0], coordinates[pointer - 1, 1]);
//Y = CalculateX2(coordinates[pointer - 1, 1], coordinates[pointer - 1, 0]);
coordinates[pointer, 0] = CalculateX1(coordinates[pointer - 1, 0], coordinates[pointer - 1, 1]);
coordinates[pointer, 1] = CalculateX2(coordinates[pointer - 1, 1], coordinates[pointer - 1, 0]);
pointer++;
if (Math.Abs(coordinates[pointer, 0]) > 1000 || Math.Abs(coordinates[pointer, 1]) > 1000)
{
Console.WriteLine("infinity");
Console.ReadKey();
}
}
for (int i = 0; i < 5000; i++)
{
Console.WriteLine("X = " + coordinates[i, 0] + "," + "Y = " + coordinates[i, 1] + "; ");
}
}
I think whatever you use to display/inspect the value cannot print ∞.
double d = double.MinValue;
d *= 2;
Console.WriteLine($"{d}: IsInfinity: {double.IsNegativeInfinity(d)}");
-∞: IsInfinity: True
Stopping at infinity
Here's a loop that stops at infinity:
double d = 2;
var i = 1;
while(!double.IsInfinity(d))
{
d = i*d*d;
i = -i;
}
Console.WriteLine(d);
-∞
I want to know when four Vector 3 positions intersect, as in the image, from point to point a1 to a2 and b1 to b2 if they intersect each other from each of their positions. Does anyone have any idea how to do this?
The Unity community wiki has a page of math functions that includes a very helpful procedure for this. Copied (and edited slightly) below:
public static bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1,
Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){
Vector3 lineVec3 = linePoint2 - linePoint1;
Vector3 crossVec1and2 = Vector3.Cross(lineVec1, lineVec2);
Vector3 crossVec3and2 = Vector3.Cross(lineVec3, lineVec2);
float planarFactor = Vector3.Dot(lineVec3, crossVec1and2);
//is coplanar, and not parallel
if( Mathf.Abs(planarFactor) < 0.0001f
&& crossVec1and2.sqrMagnitude > 0.0001f)
{
float s = Vector3.Dot(crossVec3and2, crossVec1and2)
/ crossVec1and2.sqrMagnitude;
intersection = linePoint1 + (lineVec1 * s);
return true;
}
else
{
intersection = Vector3.zero;
return false;
}
}
So, in your situation, you could use that, then check if the intersection point is between a1 and a2 and b1 and b2:
Vector3 intersection;
Vector3 aDiff = a2-a1;
Vector3 bDiff = b2-b1;
if (LineLineIntersection(out intersection, a1, aDiff, b1, bDiff))
{
float aSqrMagnitude = aDiff.sqrMagnitude;
float bSqrMagnitude = bDiff.sqrMagnitude;
if ( (intersection - a1).sqrMagnitude <= aSqrMagnitude
&& (intersection - a2).sqrMagnitude <= aSqrMagnitude
&& (intersection - b1).sqrMagnitude <= bSqrMagnitude
&& (intersection - b2).sqrMagnitude <= bSqrMagnitude)
{
// there is an intersection between the two segments and
// it is at intersection
}
}
You could also use this option if you want to dispense with the UnityEngine library:
We define a 2d vector as:
public class V2
{
public static V2 zero = new V2(0, 0);
public readonly float x;
public readonly float y;
[JsonConstructor]
public V2(float x, float y)
{
if (
physicsLogic.debugOn &&
(float.IsNaN(x) || float.IsNaN(y) || float.IsInfinity(y) || float.IsInfinity(x)))
{
throw new Exception($"Dodgy V2 ({x},{y})");
}
this.x = x; this.y = y;
}
public FieldPoint asFlooredFieldPoint()
{
return new FieldPoint(x,0,y);
}
public static V2 operator +(V2 b, V2 a) => new V2(b.x + a.x, b.y + a.y);
public static V2 operator -(V2 b, V2 a) => new V2(b.x - a.x, b.y - a.y);
public static V2 operator /(V2 a, double b) => new V2((float)(a.x / b), (float)(a.y / b));
public static V2 operator *(V2 a, double b) => new V2((float)(a.x * b), (float)(a.y * b));
public static V2 operator *(double b, V2 a) => new V2((float)(a.x * b), (float)(a.y * b));
[JsonIgnore]
float mag = -1;
[JsonIgnore]
public float magnitude
{
get
{
if (mag < 0)
{
mag = (float)Math.Sqrt(sqrMagnitude);
}
return mag;
}
}
[JsonIgnore]
public V2 normalized
{
get
{
var mag = magnitude;
if (mag == 0)
{
return V2.zero;
}
return new V2(x / mag, y / mag);
}
}
[JsonIgnore]
float _sqrMagnitude = -1;
[JsonIgnore]
public float sqrMagnitude
{
get
{
if (_sqrMagnitude < 0)
{
_sqrMagnitude = (float)(Math.Pow(x, 2) + Math.Pow(y, 2));
}
return _sqrMagnitude;
}
}
public override string ToString()
{
return $"({x.ToString("F1")},{y.ToString("F1")})";
}
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if ((obj == null) || !this.GetType().Equals(obj.GetType()))
{
return false;
}
else
{
V2 p = (V2)obj;
return (MathUtil.closeEnough(x, p.x, .001)) && (MathUtil.closeEnough(y, p.y, .001));
}
}
We look for the intersection between the two lines, if it exists:
public static V2 intersectSegment(V2 goalStart, V2 goalEnd, V2 ballStart, V2 ballEnd)
{
/* Equations of straight lines 2D: Qx + Ry + S = 0
*
* The objective is to determine the equations of the straight line of each segment,
* on the one hand the goal line and on the other hand the ball line.
*
* Then I determine if the two lines intersect at a point, or on the contrary
* if they never intersect, that is, they are parallel.
*
* If the two lines intersect at a point, I determine the value of that point (P)
*
* Finally, it is checked if this point is contained in each of the segments. *
*
*
* r1: Point A (x_A, y_A); Point B (x_B, y_B) --> AB = (x_B - x_A, y_B - y_A)
* r2: Point C (x_C, y_C), Point D (x_D, y_D) --> CD = (x_D - x_C, y_D - y_C)
*
* r1: (x - x_A)/x_AB = (y - y_A)/y_AB --> r1: Q1x + R1y + S1 = 0
* r2: (x - x_C)/x_CD = (y - y_C)/y_CD --> r2: Q2x + R2y + S2 = 0
*
* ** Q1 = y_AB ; R1 = -x_AB ; S1 = x_AB*y_A - y_AB*x_A
* ** Q2 = y_CD ; R2 = -x_CD ; S2 = x_CD*y_C - y_CD*x_C
*
* | Q1 R1 |
* determinant = | Q2 R2 | = Q1*R2 - Q2*R1
*
* ** if determinant == 0 -> is parallell
* ** if determinant != 0 -> is secant line
*
* Cut-off point (P):
*
* Q2*S1 - Q1*S2
* y_P = -------------
* Q1*R2 - Q2*R1
*
* S1*(Q2*R1 - Q1*R2) + R1*Q2*(Q1 - S1)
* x_P = ------------------------------------
* Q1^2*R2 - Q1*Q2*R1
*
*
* ** if P c in AB or CD -> Intersection true
*
*/
var goalVector = goalEnd - goalStart;
var ballVector = ballEnd - ballStart;
var Q1 = goalVector.y;
var Q2 = ballVector.y;
var R1 = goalVector.x;
var R2 = ballVector.x;
var S1 = goalVector.x * goalStart.y - goalVector.y * goalStart.x;
var S2 = ballVector.x * ballStart.y - ballVector.y * ballStart.x;
var determinant = Q1 * R2 - Q2 * R1;
if (determinant != 0)
{
var x_P = (S2 * R1 - R2 * S1) / (R2 * Q1 - Q2 * R1);
var y_P = (S2 * Q1 - Q2 * S1) / (R2 * Q1 - Q2 * R1);
var intersectPoint = new V2(x_P, y_P);
if (MathUtil.PointContentInAB(goalStart, goalEnd, intersectPoint ) &&
MathUtil.PointContentInAB(ballStart, ballEnd, intersectPoint))
{
return intersectPoint;
}
}
return null;
}
Then, We return true or false if there is such an intersection between the two lines:
public static bool findIfIntersectsInSegment(V2 goalStart, V2 goalEnd, V2 ballStart, V2 ballEnd)
{
return intersectSegment(goalStart, goalEnd, ballStart, ballEnd)!=null;
}
Finally, if the intersection exists, we look for the intersection point of the two lines:
public static bool PointContentInAB(V2 A, V2 B, V2 P)
{
/* Equations of straight lines 2D: Qx + Ry + S = 0
*
* Point A (x_A, y_A); Point B (x_B, y_B) --> AB = (x_B - x_A, y_B - y_A)
*
* r1: (x - x_A)/x_AB = (y - y_A)/y_AB --> r1: Q1x + R1y + S1 = 0
* Q1 = y_AB ; R1 = -x_AB ; S1 = x_AB*y_A - y_AB*x_A
*
* ** if P.x <= B.x && P.x >= A.x --> Point content in AB
*/
var AB = B - A;
var P_content_in_r1 = AB.y * P.x - AB.x * P.y + (AB.x * A.y - AB.y * A.x);
if (nearzero(P_content_in_r1))
// Point content in r1
{
if (AB.x > 0f)
{
if (P.x <= B.x && P.x >= A.x)
// Point content in r1 and AB
{
if (AB.y > 0f)
{
if (P.y <= B.y && P.y >= A.y)
{
return true;
}
}
else
{
if(P.y >= B.y && P.y <= A.y)
{
return true;
}
}
}
}
else
{
if (P.x >= B.x && P.x <= A.x)
{
// Point content in r1 and AB
if (AB.y > 0f)
{
if (P.y <= B.y && P.y >= A.y)
{
return true;
}
}
else
{
if (P.y >= B.y && P.y <= A.y)
{
return true;
}
}
}
}
}
return false;
}
I hope you find it useful, best regards.
I'd like to make a scientific calculator in C#, but I didn't find gamma function to
calculate fractal factorials.
The function's description is below:
https://en.wikipedia.org/wiki/Gamma_function
How can I reach gamma function in C#?
Install the Math.NET package from nuget
Documentation on the Gamma Function : https://numerics.mathdotnet.com/Functions.html
The Math.NET package is indeed an easy way to get the gamma function. Please keep in mind that gamma(x) is equal to (x-1)!. So, gamma(4.1) = 6.813 while 4.1! = 27.932. To get 4.1! from gamma(4.1), you can multiply gamma(4.1) by 4.1, or simply take the gamma of 5.1 instead. (I see no need to show a bunch of digits of precision here.)
In C#:
using MathNet.Numerics; //at beginning of program
private double Factorial(double x)
{
double r = x;
r *= SpecialFunctions.Gamma(x);
return r;
//This could be simplified into:
//return x * SpecialFunctions.Gamma(x);
}
private double Factorial2(double x)
{
double r;
r = SpecialFunctions.Gamma(x + 1);
return r;
}
If for some reason you don't want to use Math.Net, you can write your own gamma function as follows:
static int g = 7;
static double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
771.32342877765313, -176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
Complex MyGamma(Complex z)
{
// Reflection formula
if (z.Real < 0.5)
{
return Math.PI / (Complex.Sin(Math.PI * z) * MyGamma(1 - z));
}
else
{
z -= 1;
Complex x = p[0];
for (var i = 1; i < g + 2; i++)
{
x += p[i] / (z + i);
}
Complex t = z + g + 0.5;
return Complex.Sqrt(2 * Math.PI) * (Complex.Pow(t, z + 0.5)) * Complex.Exp(-t) * x;
}
}
Note that you can replace the data type Complex with double and the Complex. functions with Math. if you don't need complex numbers, like so:
double MyGammaDouble(double z)
{
if (z < 0.5)
return Math.PI / (Math.Sin(Math.PI * z) * MyGammaDouble(1 - z));
z -= 1;
double x = p[0];
for (var i = 1; i < g + 2; i++)
x += p[i] / (z + i);
double t = z + g + 0.5;
return Math.Sqrt(2 * Math.PI) * (Math.Pow(t, z + 0.5)) * Math.Exp(-t) * x;
}
This is from an old wiki page (which has been replaced) but is copied here.
I'm getting an exception when I'm trying to run my program.. It seems to me it's working well but I'm missing something as it appears.
public Coord LatLonToUTMXY(double lat, double lon)
{
Coord co = new Coord();
co.zone = Math.Floor((lon + 180.0) / 6) + 1;
//double zone = Math.Floor((lon + 180.0) / 6) + 1;
MapLatLonToXY(DegToRad(lat), DegToRad(lon), UTMCentralMeridian(co.zone), co.eastNorth);
/* Adjust easting and northing for UTM system. */
co.eastNorth[0] = co.eastNorth[0] * UTMScaleFactor + 500000.0;
co.eastNorth[1] = co.eastNorth[1] * UTMScaleFactor;
if (co.eastNorth[1] < 0.0)
co.eastNorth[1] = co.eastNorth[1] + 10000000.0;
return co;
}
I'm getting the exception here ...
public void MapLatLonToXY(double phi, double lambda, double lambda0, double [] xy)
{
//Some previous code
//Exception for xy[0] ....!
xy[0] = N * Math.Cos(phi) * l
+ (N / 6.0 * Math.Pow(Math.Cos(phi), 3.0) * l3coef * Math.Pow(l, 3.0))
+ (N / 120.0 * Math.Pow(Math.Cos(phi), 5.0) * l5coef * Math.Pow(l, 5.0))
+ (N / 5040.0 * Math.Pow(Math.Cos(phi), 7.0) * l7coef * Math.Pow(l, 7.0));
/* Calculate northing (y) */
xy[1] = ArcLengthOfMeridian(phi)
+ (t / 2.0 * N * Math.Pow(Math.Cos(phi), 2.0) * Math.Pow(l, 2.0))
+ (t / 24.0 * N * Math.Pow(Math.Cos(phi), 4.0) * l4coef * Math.Pow(l, 4.0))
+ (t / 720.0 * N * Math.Pow(Math.Cos(phi), 6.0) * l6coef * Math.Pow(l, 6.0))
+ (t / 40320.0 * N * Math.Pow(Math.Cos(phi), 8.0) * l8coef * Math.Pow(l, 8.0));
return;
}
for the co it's a struct
public struct Coord
{
public double zone;
public double[] eastNorth;
}
What am I missing here ?
Thanks
This is happening because the xy array in your function (which comes from Coord.eastNorth is uninitialized. I noticed that Coord was a struct and not a class.. any particular reason? This would work if Coord was a class
public class Coord
{
public double Zone {get; set;}
public List<double> EastNorth {get; set;}
public Coord()
{
EastNorth = new List<double>();
}
}
public List<double> MapLatLonToXY(double phi, double lambda, double lambda0)
{
var xy = new List<double>();
//Exception for xy[0] ....!
xy.Add(N * Math.Cos(phi) * l
+ (N / 6.0 * Math.Pow(Math.Cos(phi), 3.0) * l3coef * Math.Pow(l, 3.0))
+ (N / 120.0 * Math.Pow(Math.Cos(phi), 5.0) * l5coef * Math.Pow(l, 5.0))
+ (N / 5040.0 * Math.Pow(Math.Cos(phi), 7.0) * l7coef * Math.Pow(l, 7.0)));
/* Calculate northing (y) */
xy.Add(ArcLengthOfMeridian(phi)
+ (t / 2.0 * N * Math.Pow(Math.Cos(phi), 2.0) * Math.Pow(l, 2.0))
+ (t / 24.0 * N * Math.Pow(Math.Cos(phi), 4.0) * l4coef * Math.Pow(l, 4.0))
+ (t / 720.0 * N * Math.Pow(Math.Cos(phi), 6.0) * l6coef * Math.Pow(l, 6.0))
+ (t / 40320.0 * N * Math.Pow(Math.Cos(phi), 8.0) * l8coef * Math.Pow(l, 8.0)));
return xy;
}
public Coord LatLonToUTMXY(double lat, double lon)
{
Coord co = new Coord();
co.zone = Math.Floor((lon + 180.0) / 6) + 1;
//double zone = Math.Floor((lon + 180.0) / 6) + 1;
co.EastNorth = MapLatLonToXY(DegToRad(lat), DegToRad(lon), UTMCentralMeridian(co.zone));
/* Adjust easting and northing for UTM system. */
co.EastNorth[0] = co.EastNorth[0] * UTMScaleFactor + 500000.0;
co.EastNorth[1] = co.EastNorth[1] * UTMScaleFactor;
if (co.EastNorth[1] < 0.0)
co.EastNorth[1] = co.EastNorth[1] + 10000000.0;
return co;
}
I'm trying to convert a RGB32 value to HSL because I want to use the Hue component.
I have used some examples that I found online to create this class:
public class HSLColor
{
public Double Hue;
public Double Saturation;
public Double Luminosity;
public HSLColor(Double H, Double S, Double L)
{
Hue = H;
Saturation = S;
Luminosity = L;
}
public static HSLColor FromRGB(Color Clr)
{
return FromRGB(Clr.R, Clr.G, Clr.B);
}
public static HSLColor FromRGB(Byte R, Byte G, Byte B)
{
Double _R = (R / 255d);
Double _G = (G / 255d);
Double _B = (B / 255d);
Double _Min = Math.Min(Math.Min(_R, _G), _B);
Double _Max = Math.Max(Math.Max(_R, _G), _B);
Double _Delta = _Max - _Min;
Double H = 0;
Double S = 0;
Double L = (float)((_Max + _Min) / 2.0f);
if (_Delta != 0)
{
if (L < 0.5d)
{
S = (float)(_Delta / (_Max + _Min));
}
else
{
S = (float)(_Delta / (2.0f - _Max - _Min));
}
if (_R == _Max)
{
H = (_G - _B) / _Delta;
}
else if (_G == _Max)
{
H = 2f + (_B - _R) / _Delta;
}
else if (_B == _Max)
{
H = 4f + (_R - _G) / _Delta;
}
}
//Convert to degrees
H = H * 60d;
if (H < 0) H += 360;
//Convert to percent
S *= 100d;
L *= 100d;
return new HSLColor(H, S, L);
}
private Double Hue_2_RGB(Double v1, Double v2, Double vH)
{
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6.0d * vH) < 1) return (v1 + (v2 - v1) * 6 * vH);
if ((2.0d * vH) < 1) return (v2);
if ((3.0d * vH) < 2) return (v1 + (v2 - v1) * ((2.0d / 3.0d) - vH) * 6.0d);
return (v1);
}
public Color ToRGB()
{
Color Clr = new Color();
Double var_1, var_2;
if (Saturation == 0)
{
Clr.R = (Byte)(Luminosity * 255);
Clr.G = (Byte)(Luminosity * 255);
Clr.B = (Byte)(Luminosity * 255);
}
else
{
if (Luminosity < 0.5) var_2 = Luminosity * (1 + Saturation);
else var_2 = (Luminosity + Saturation) - (Saturation * Luminosity);
var_1 = 2 * Luminosity - var_2;
Clr.R = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue + (1 / 3)));
Clr.G = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue));
Clr.B = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue - (1 / 3)));
}
return Clr;
}
}
However it doesn't seem to work correctly,
If I use an input color of (R 0, G 255, B 193) for example:
I get Hue = 0
while in photoshop if I choose the exact same RGB values I get:
Hue = 165
which is the correct value.
I want the Hue to be a value ranging from 0 to 360 or 0 to 240
What is the problem?..
Reference:
EasyRGB RGB->HSL
R / 255
this is integer division, meaning you get either 0 or 1. try:
(float)R / 255
and for all other cases.
for constants try:
( 1 / 3 ) -> ( 1.0 / 3.0 )
The below is open source mixture of Drupal + some various programmers work mixed into one single function boasting RGB > HSL and back. It works flawlessly.
<?php
### RGB >> HSL
function _color_rgb2hsl($rgb) {
$r = $rgb[0]; $g = $rgb[1]; $b = $rgb[2];
$min = min($r, min($g, $b)); $max = max($r, max($g, $b));
$delta = $max - $min; $l = ($min + $max) / 2; $s = 0;
if ($l > 0 && $l < 1) {
$s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
}
$h = 0;
if ($delta > 0) {
if ($max == $r && $max != $g) $h += ($g - $b) / $delta;
if ($max == $g && $max != $b) $h += (2 + ($b - $r) / $delta);
if ($max == $b && $max != $r) $h += (4 + ($r - $g) / $delta);
$h /= 6;
} return array($h, $s, $l);
}
### HSL >> RGB
function _color_hsl2rgb($hsl) {
$h = $hsl[0]; $s = $hsl[1]; $l = $hsl[2];
$m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l*$s;
$m1 = $l * 2 - $m2;
return array(_color_hue2rgb($m1, $m2, $h + 0.33333),
_color_hue2rgb($m1, $m2, $h),
_color_hue2rgb($m1, $m2, $h - 0.33333));
}
### Helper function for _color_hsl2rgb().
function _color_hue2rgb($m1, $m2, $h) {
$h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
if ($h * 6 < 1) return $m1 + ($m2 - $m1) * $h * 6;
if ($h * 2 < 1) return $m2;
if ($h * 3 < 2) return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
return $m1;
}
### Convert a hex color into an RGB triplet.
function _color_unpack($hex, $normalize = false) {
if (strlen($hex) == 4) {
$hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
} $c = hexdec($hex);
for ($i = 16; $i >= 0; $i -= 8) {
$out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
} return $out;
}
### Convert an RGB triplet to a hex color.
function _color_pack($rgb, $normalize = false) {
foreach ($rgb as $k => $v) {
$out |= (($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
}return '#'. str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
}
print "Hex: ";
$testhex = "#b7b700";
print $testhex;
$testhex2rgb = _color_unpack($testhex,true);
print "<br />RGB: ";
var_dump($testhex2rgb);
print "<br />HSL color module: ";
$testrgb2hsl = _color_rgb2hsl($testhex2rgb); //Convert to HSL
var_dump($testrgb2hsl);
print "<br />RGB: ";
$testhsl2rgb = _color_hsl2rgb($testrgb2hsl); // And back to RGB
var_dump($testhsl2rgb);
print "<br />Hex: ";
$testrgb2hex = _color_pack($testhsl2rgb,true);
var_dump($testrgb2hex);
?>