Beispiel #1
0
        /// <summary>
        /// 返回一个以 "d° m′ s″ " 格式表示角度的字符串。
        /// </summary>
        /// <param name="degree">以角度为单位的角度。</param>
        /// <param name="decimalDigits">保留的小数位数,0 表示不保留小数,-1 表示保留所有小数。</param>
        /// <param name="cutdownIdleZeros">是否删除小数点后所有不必要的 "0"。</param>
        /// <returns>字符串,表示以 "d° m′ s″ " 格式表示的角度。</returns>
        public static string GetAngleStringOfDegree(double degree, int decimalDigits, bool cutdownIdleZeros)
        {
            if (InternalMethod.IsNaNOrInfinity(degree))
            {
                return("N/A");
            }
            else
            {
                string Sign = (degree < 0 ? "-" : string.Empty);
                degree = Math.Abs(degree);

                double DegF = degree;
                double DegD = Math.Floor(DegF);
                double MinF = (DegF - DegD) * 60;
                double MinD = Math.Floor(MinF);
                double SecF = (MinF - MinD) * 60;

                string DegStr = DegD + "° ";
                string MinStr = MinD + "′ ";
                string SecStr = SecF.ToString(decimalDigits >= 0 ? "N" + Math.Min(16, decimalDigits) : string.Empty) + "″ ";

                if (cutdownIdleZeros)
                {
                    int DotIndex = SecStr.IndexOf('.');

                    if (DotIndex >= 0)
                    {
                        int LastPartIndex = DotIndex + 1;

                        while (LastPartIndex < SecStr.Length && char.IsDigit(SecStr, LastPartIndex))
                        {
                            LastPartIndex++;
                        }

                        string HeadPart   = SecStr.Substring(0, DotIndex);
                        string MiddlePart = SecStr.Substring(DotIndex, LastPartIndex - DotIndex);
                        string LastPart   = (LastPartIndex < SecStr.Length ? SecStr.Substring(LastPartIndex) : string.Empty);

                        if (MiddlePart.Length > 0)
                        {
                            while (MiddlePart[MiddlePart.Length - 1] == '0')
                            {
                                MiddlePart = MiddlePart.Substring(0, MiddlePart.Length - 1);
                            }

                            if (MiddlePart.Length == 1)
                            {
                                MiddlePart = string.Empty;
                            }
                        }

                        SecStr = string.Concat(HeadPart, MiddlePart, LastPart);
                    }
                }

                return(string.Concat(Sign, DegStr, MinStr, SecStr));
            }
        }
Beispiel #2
0
 /// <summary>
 /// 计算椭圆在指定相位的焦半径。
 /// </summary>
 /// <param name="semiMajorAxis">椭圆的半长轴。</param>
 /// <param name="eccentricity">椭圆的离心率。</param>
 /// <param name="phase">椭圆的相位(弧度)(以近焦点相位为 0 弧度,从 +X 轴指向 +Y 轴的方向为正方向)。</param>
 /// <returns>双精度浮点数,表示椭圆在指定相位的焦半径。</returns>
 public static double GetFocalRadiusOfEllipse(double semiMajorAxis, double eccentricity, double phase)
 {
     if ((InternalMethod.IsNaNOrInfinity(semiMajorAxis) || semiMajorAxis <= 0) || (InternalMethod.IsNaNOrInfinity(eccentricity) || eccentricity < 0 || eccentricity >= 1) || InternalMethod.IsNaNOrInfinity(phase))
     {
         return(double.NaN);
     }
     else
     {
         return(semiMajorAxis * Math.Sqrt(Math.Pow(Math.Cos(phase) - eccentricity, 2) + (1 - Math.Pow(eccentricity, 2)) * Math.Pow(Math.Sin(phase), 2)));
     }
 }
Beispiel #3
0
 /// <summary>
 /// 判断在一个圆内部能否看到一个点。
 /// </summary>
 /// <param name="pt">点。</param>
 /// <param name="offset">圆的圆心。</param>
 /// <param name="radius">圆的半径。</param>
 /// <returns>布尔值,表示在一个圆内部能否看到一个点。</returns>
 public static bool PointIsVisibleInCircle(PointD pt, PointD offset, double radius)
 {
     if (pt.IsNaNOrInfinity || offset.IsNaNOrInfinity || (InternalMethod.IsNaNOrInfinity(radius) || radius <= 0))
     {
         return(false);
     }
     else
     {
         return(pt.DistanceFrom(offset) < radius);
     }
 }
Beispiel #4
0
 /// <summary>
 /// 将椭圆的圆心角转换为相位(弧度)(以近焦点相位为 0 弧度,从 +X 轴指向 +Y 轴的方向为正方向)。
 /// </summary>
 /// <param name="centralAngle">椭圆的圆心角(弧度)。</param>
 /// <param name="eccentricity">椭圆的离心率。</param>
 /// <returns>双精度浮点数,表示将椭圆的圆心角转换为相位(弧度)(以近焦点相位为 0 弧度,从 +X 轴指向 +Y 轴的方向为正方向)得到的结果。</returns>
 public static double EllipseCentralAngleToPhase(double centralAngle, double eccentricity)
 {
     if (InternalMethod.IsNaNOrInfinity(centralAngle) || (InternalMethod.IsNaNOrInfinity(eccentricity) || eccentricity < 0 || eccentricity >= 1))
     {
         return(double.NaN);
     }
     else
     {
         return(Math.Atan(Math.Tan(centralAngle) / Math.Sqrt(1 - Math.Pow(eccentricity, 2))) + Math.Round(centralAngle / Constant.Pi) * Constant.Pi);
     }
 }
Beispiel #5
0
        /// <summary>
        /// 返回将一个时间间隔在合适的单位下保留指定位数有效数字的数值。
        /// </summary>
        /// <param name="seconds">时间间隔(秒)。</param>
        /// <param name="significance">有效数字位数,0 表示保留所有有效数字。</param>
        /// <returns>双精度浮点数,表示将一个时间间隔在合适的单位下保留指定位数有效数字的数值。</returns>
        public static double GetStandardizationTimespanOfSecond(double seconds, int significance)
        {
            if (InternalMethod.IsNaNOrInfinity(seconds))
            {
                return(double.NaN);
            }
            else
            {
                if (seconds != 0 && significance > 0)
                {
                    int sign = Math.Sign(seconds);

                    seconds = Math.Abs(seconds);

                    double unit = 1;

                    if (seconds >= 31557600.0)
                    {
                        seconds /= (unit = 31557600.0);
                    }
                    else if (seconds >= 86400.0)
                    {
                        seconds /= (unit = 86400.0);
                    }
                    else if (seconds >= 3600.0)
                    {
                        seconds /= (unit = 3600.0);
                    }
                    else if (seconds >= 60.0)
                    {
                        seconds /= (unit = 60.0);
                    }
                    else if (seconds < 1)
                    {
                        seconds /= (unit = 0.001);
                    }

                    int exp = (int)Math.Floor(Math.Log10(Math.Abs(seconds))) - Math.Max(0, significance - 1);

                    seconds = Math.Round(seconds / Math.Pow(10, exp));

                    while (seconds >= 10)
                    {
                        seconds /= 10;
                        exp++;
                    }

                    seconds *= (sign * Math.Pow(10, exp) * unit);
                }

                return(seconds);
            }
        }
Beispiel #6
0
        /// <summary>
        /// 判断在一个菱形内部能否看到一个点。
        /// </summary>
        /// <param name="pt">点。</param>
        /// <param name="offset">菱形的中心。</param>
        /// <param name="semiMajorAxis">菱形的半长轴。</param>
        /// <param name="semiMinorAxis">菱形的半短轴。</param>
        /// <param name="rotateAngle">菱形的旋转角(弧度)(以焦点为中心,以 +X 轴为 0 弧度,从 +X 轴指向 +Y 轴的方向为正方向,半长轴相对于 +X 轴的角度)。</param>
        /// <returns>布尔值,表示在一个菱形内部能否看到一个点。</returns>
        public static bool PointIsVisibleInRhombus(PointD pt, PointD offset, double semiMajorAxis, double semiMinorAxis, double rotateAngle)
        {
            if (pt.IsNaNOrInfinity || offset.IsNaNOrInfinity || (InternalMethod.IsNaNOrInfinity(semiMajorAxis) || semiMajorAxis <= 0) || (InternalMethod.IsNaNOrInfinity(semiMinorAxis) || semiMinorAxis <= 0) || InternalMethod.IsNaNOrInfinity(rotateAngle))
            {
                return(false);
            }
            else
            {
                pt.Rotate(-rotateAngle, offset);

                return(Math.Abs(pt.X - offset.X) * semiMinorAxis + Math.Abs(pt.Y - offset.Y) * semiMajorAxis < semiMajorAxis * semiMinorAxis);
            }
        }
Beispiel #7
0
        /// <summary>
        /// 判断在一个椭圆内部能否看到一个点。
        /// </summary>
        /// <param name="pt">点。</param>
        /// <param name="offset">椭圆的焦点。</param>
        /// <param name="semiMajorAxis">椭圆的半长轴。</param>
        /// <param name="eccentricity">椭圆的离心率。</param>
        /// <param name="rotateAngle">椭圆的旋转角(弧度)(以焦点为中心,以 +X 轴为 0 弧度,从 +X 轴指向 +Y 轴的方向为正方向,焦点到近焦点连线相对于 +X 轴的角度)。</param>
        /// <returns>布尔值,表示在一个椭圆内部能否看到一个点。</returns>
        public static bool PointIsVisibleInEllipse(PointD pt, PointD offset, double semiMajorAxis, double eccentricity, double rotateAngle)
        {
            if (pt.IsNaNOrInfinity || offset.IsNaNOrInfinity || (InternalMethod.IsNaNOrInfinity(semiMajorAxis) || semiMajorAxis <= 0) || (InternalMethod.IsNaNOrInfinity(eccentricity) || eccentricity < 0 || eccentricity >= 1) || InternalMethod.IsNaNOrInfinity(rotateAngle))
            {
                return(false);
            }
            else
            {
                PointD _Offset = new PointD(offset.X - 2 * semiMajorAxis * eccentricity * Math.Cos(rotateAngle), offset.Y - 2 * semiMajorAxis * eccentricity * Math.Sin(rotateAngle));

                double FocalDistSum = pt.DistanceFrom(offset) + pt.DistanceFrom(_Offset);

                return(FocalDistSum < 2 * semiMajorAxis);
            }
        }
Beispiel #8
0
        /// <summary>
        /// 返回将一个距离在合适的单位下保留指定位数有效数字的数值。
        /// </summary>
        /// <param name="meters">距离(米)。</param>
        /// <param name="significance">有效数字位数,0 表示保留所有有效数字。</param>
        /// <returns>双精度浮点数,表示将一个距离在合适的单位下保留指定位数有效数字的数值。</returns>
        public static double GetStandardizationDistanceOfMeter(double meters, int significance)
        {
            if (InternalMethod.IsNaNOrInfinity(meters))
            {
                return(double.NaN);
            }
            else
            {
                if (meters != 0 && significance > 0)
                {
                    int sign = Math.Sign(meters);

                    meters = Math.Abs(meters);

                    double unit = 1;

                    if (meters >= 9460730472580800.0)
                    {
                        meters /= (unit = 9460730472580800.0);
                    }
                    else if (meters >= 149597870700.0)
                    {
                        meters /= (unit = 149597870700.0);
                    }
                    else if (meters >= 1000.0)
                    {
                        meters /= (unit = 1000.0);
                    }

                    int exp = (int)Math.Floor(Math.Log10(Math.Abs(meters))) - Math.Max(0, significance - 1);

                    meters = Math.Round(meters / Math.Pow(10, exp));

                    while (meters >= 10)
                    {
                        meters /= 10;
                        exp++;
                    }

                    meters *= (sign * Math.Pow(10, exp) * unit);
                }

                return(meters);
            }
        }
Beispiel #9
0
 /// <summary>
 /// 计算平面直角坐标系中过一个定点到一条直线的距离。
 /// </summary>
 /// <param name="pt">定点。</param>
 /// <param name="A">直线的一般式方程的第一个参数。</param>
 /// <param name="B">直线的一般式方程的第二个参数。</param>
 /// <param name="C">直线的一般式方程的第三个参数。</param>
 /// <returns>双精度浮点数,表示平面直角坐标系中过一个定点到一条直线的距离。</returns>
 public static double GetDistanceBetweenPointAndLine(PointD pt, double A, double B, double C)
 {
     if (pt.IsNaNOrInfinity || InternalMethod.IsNaNOrInfinity(A) || InternalMethod.IsNaNOrInfinity(B) || InternalMethod.IsNaNOrInfinity(C))
     {
         return(double.NaN);
     }
     else
     {
         if (A == 0 && B == 0)
         {
             return(double.NaN);
         }
         else
         {
             return((A * pt.X + B * pt.Y + C) / Math.Sqrt(A * A + B * B));
         }
     }
 }
Beispiel #10
0
        //

        private static double _CheckLevel(double level) // 对双精度浮点数表示的调整程度的值进行合法性检查,返回合法的值。
        {
            if (InternalMethod.IsNaNOrInfinity(level))
            {
                throw new ArgumentOutOfRangeException();
            }

            //

            if (level < -100)
            {
                if (level <= -100 - 5E-11)
                {
                    throw new ArgumentOutOfRangeException();
                }

                return(-1);
            }
            else if (level > 100)
            {
                if (level >= 100 + 5E-11)
                {
                    throw new ArgumentOutOfRangeException();
                }

                return(1);
            }
            else
            {
                if (level < -1 || level > 1)
                {
                    return(level / 100);
                }
                else
                {
                    return(level);
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// 返回一个表示距离的字符串。
        /// </summary>
        /// <param name="meters">距离(米)。</param>
        /// <returns>字符串,表示距离。</returns>
        public static string GetLargeDistanceStringOfMeter(double meters)
        {
            if (InternalMethod.IsNaNOrInfinity(meters))
            {
                return("N/A");
            }
            else
            {
                if (meters == 0)
                {
                    return("0");
                }
                else
                {
                    int Sign = Math.Sign(meters);

                    meters = Math.Abs(meters);

                    return((Sign == -1 ? "-" : string.Empty) + (meters >= 9460730472580800E12 ? meters / 9460730472580800E12 + " Tly" : (meters >= 9460730472580800E9 ? meters / 9460730472580800E9 + " Gly" : (meters >= 9460730472580800E6 ? meters / 9460730472580800E6 + " Mly" : (meters >= 9460730472580800E3 ? meters / 9460730472580800E3 + " kly" : (meters >= 9460730472580800.0 ? meters / 9460730472580800.0 + " ly" : (meters >= 149597870700.0 ? meters / 149597870700.0 + " AU" : (meters >= 1000.0 ? meters / 1000.0 + " km" : meters + " m"))))))));
                }
            }
        }
Beispiel #12
0
        /// <summary>
        /// 返回一个表示时间间隔的字符串。
        /// </summary>
        /// <param name="seconds">时间间隔(秒)。</param>
        /// <returns>字符串,表示时间间隔。</returns>
        public static string GetLargeTimespanStringOfSecond(double seconds)
        {
            if (InternalMethod.IsNaNOrInfinity(seconds))
            {
                return("N/A");
            }
            else
            {
                if (seconds == 0)
                {
                    return("0");
                }
                else
                {
                    int Sign = Math.Sign(seconds);

                    seconds = Math.Abs(seconds);

                    return((Sign == -1 ? "-" : string.Empty) + (seconds >= 31557600E12 ? seconds / (31557600E12) + " Ta" : (seconds >= 31557600E9 ? seconds / (31557600E9) + " Ga" : (seconds >= 31557600E6 ? seconds / (31557600E6) + " Ma" : (seconds >= 31557600E3 ? seconds / (31557600E3) + " ka" : (seconds >= 31557600.0 ? seconds / 31557600.0 + " a" : (seconds >= 86400.0 ? seconds / 86400.0 + " d" : (seconds >= 3600.0 ? seconds / 3600.0 + " h" : (seconds >= 60 ? seconds / 60.0 + " min" : (seconds >= 1 ? seconds + " s" : seconds * 1000.0 + " ms"))))))))));
                }
            }
        }
Beispiel #13
0
        //

        private static double _CheckProportion(double proportion) // 对双精度浮点数表示的比例的值进行合法性检查,返回合法的值。
        {
            if (InternalMethod.IsNaNOrInfinity(proportion))
            {
                throw new ArgumentOutOfRangeException();
            }

            //

            if (proportion < 0)
            {
                if (proportion <= -5E-13)
                {
                    throw new ArgumentOutOfRangeException();
                }

                return(0);
            }
            else if (proportion > 100)
            {
                if (proportion >= 100 + 5E-11)
                {
                    throw new ArgumentOutOfRangeException();
                }

                return(1);
            }
            else
            {
                if (proportion > 1)
                {
                    return(proportion / 100);
                }
                else
                {
                    return(proportion);
                }
            }
        }
Beispiel #14
0
        //

        /// <summary>
        /// 将一个角度映射到范围为一个周角的区间。
        /// </summary>
        /// <param name="angle">用于转换的角度。</param>
        /// <param name="asDegree">用于转换的角度是否以角度制表示。</param>
        /// <param name="zeroCentered">目标区间是否以 0 为中心。</param>
        /// <returns>双精度浮点数,表示将一个角度映射到范围为一个周角的区间得到的结果。</returns>
        public static double AngleMapping(double angle, bool asDegree, bool zeroCentered)
        {
            if (InternalMethod.IsNaNOrInfinity(angle))
            {
                return(double.NaN);
            }
            else
            {
                double result = angle;

                double perigon = (asDegree ? 360 : Constant.DoublePi);

                if (angle < 0 || angle >= perigon)
                {
                    result = angle - Math.Floor(angle / perigon) * perigon;
                }

                if (zeroCentered)
                {
                    double flat = (asDegree ? 180 : Constant.Pi);

                    if (result >= flat)
                    {
                        return(result - flat);
                    }
                    else
                    {
                        return(result);
                    }
                }
                else
                {
                    return(result);
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// 判断在一个圆内部能否看到一个直线段的部分或全部。
        /// </summary>
        /// <param name="pt1">直线段的第一个端点。</param>
        /// <param name="pt2">直线段的第二个端点。</param>
        /// <param name="offset">圆的圆心。</param>
        /// <param name="radius">圆的半径。</param>
        /// <returns>布尔值,表示在一个圆内部能否看到一个直线段的部分或全部。</returns>
        public static bool LineIsVisibleInCircle(PointD pt1, PointD pt2, PointD offset, double radius)
        {
            if (pt1.IsNaNOrInfinity || pt2.IsNaNOrInfinity || offset.IsNaNOrInfinity || (InternalMethod.IsNaNOrInfinity(radius) || radius <= 0))
            {
                return(false);
            }
            else
            {
                double Dist_Off_P1 = offset.DistanceFrom(pt1);
                double Dist_Off_P2 = offset.DistanceFrom(pt2);

                if (Dist_Off_P1 <= radius || Dist_Off_P2 <= radius)
                {
                    return(true);
                }
                else
                {
                    double A, B, C;

                    CalcLineGeneralFunction(pt1, pt2, out A, out B, out C);

                    double Dist_Off_FP = GetDistanceBetweenPointAndLine(offset, A, B, C);

                    if (Dist_Off_FP > radius)
                    {
                        return(false);
                    }
                    else
                    {
                        if ((A * pt1.X + B * pt1.Y + C) * (A * pt2.X + B * pt2.Y + C) > 0)
                        {
                            return(false);
                        }
                        else
                        {
                            return(true);
                        }
                    }
                }
            }
        }
Beispiel #16
0
 /// <summary>
 /// 将位图的副本按顺时针方向旋转一个角度,返回旋转后得到的位图。
 /// </summary>
 /// <param name="bmp">用于旋转的位图。</param>
 /// <param name="rotateAngle">按顺时针方向旋转的角度(弧度)。</param>
 /// <param name="antiAlias">是否使用抗锯齿模式绘图。</param>
 /// <returns>Bitmap 对象,表示将位图的副本按顺时针方向旋转一个角度得到的结果。</returns>
 public static Bitmap RotateBitmap(Bitmap bmp, double rotateAngle, bool antiAlias)
 {
     if (bmp is null || InternalMethod.IsNaNOrInfinity(rotateAngle))
     {
         return(null);
     }
Beispiel #17
0
 /// <summary>
 /// 判断在一个矩形内部能否看到一个圆的内部或者圆周的部分或全部。
 /// </summary>
 /// <param name="offset">圆的圆心。</param>
 /// <param name="radius">圆的半径。</param>
 /// <param name="rect">矩形。</param>
 /// <returns>布尔值,表示在一个矩形内部能否看到一个圆的内部或者圆周的部分或全部。</returns>
 public static bool CircleInnerIsVisibleInRectangle(PointD offset, double radius, RectangleF rect)
 {
     if (offset.IsNaNOrInfinity || (InternalMethod.IsNaNOrInfinity(radius) || radius <= 0) || rect.Size.IsEmpty)
     {
         return(false);
     }
     else
     {
         if (offset.X < rect.X && offset.Y < rect.Y)
         {
             if (Math.Pow(offset.X - rect.X, 2) + Math.Pow(offset.Y - rect.Y, 2) < Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X > rect.Right && offset.Y < rect.Y)
         {
             if (Math.Pow(offset.X - rect.Right, 2) + Math.Pow(offset.Y - rect.Y, 2) < Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X < rect.X && offset.Y > rect.Bottom)
         {
             if (Math.Pow(offset.X - rect.X, 2) + Math.Pow(offset.Y - rect.Bottom, 2) < Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X > rect.Right && offset.Y > rect.Bottom)
         {
             if (Math.Pow(offset.X - rect.Right, 2) + Math.Pow(offset.Y - rect.Bottom, 2) < Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X >= rect.X - radius && offset.X <= rect.Right + radius && offset.Y >= rect.Y - radius && offset.Y <= rect.Bottom + radius)
         {
             return(true);
         }
         else
         {
             return(false);
         }
     }
 }
Beispiel #18
0
 /// <summary>
 /// 判断在一个矩形内部能否看到一个圆的圆周的部分或全部。
 /// </summary>
 /// <param name="offset">圆的圆心。</param>
 /// <param name="radius">圆的半径。</param>
 /// <param name="rect">矩形。</param>
 /// <returns>布尔值,表示在一个矩形内部能否看到一个圆的圆周的部分或全部。</returns>
 public static bool CircumferenceIsVisibleInRectangle(PointD offset, double radius, RectangleF rect)
 {
     if (offset.IsNaNOrInfinity || (InternalMethod.IsNaNOrInfinity(radius) || radius <= 0) || rect.Size.IsEmpty)
     {
         return(false);
     }
     else
     {
         if (offset.X < rect.X && offset.Y < rect.Y)
         {
             if (Math.Pow(offset.X - rect.X, 2) + Math.Pow(offset.Y - rect.Y, 2) < Math.Pow(radius, 2) && Math.Pow(offset.X - rect.Right, 2) + Math.Pow(offset.Y - rect.Bottom, 2) > Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X > rect.Right && offset.Y < rect.Y)
         {
             if (Math.Pow(offset.X - rect.Right, 2) + Math.Pow(offset.Y - rect.Y, 2) < Math.Pow(radius, 2) && Math.Pow(offset.X - rect.X, 2) + Math.Pow(offset.Y - rect.Bottom, 2) > Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X < rect.X && offset.Y > rect.Bottom)
         {
             if (Math.Pow(offset.X - rect.X, 2) + Math.Pow(offset.Y - rect.Bottom, 2) < Math.Pow(radius, 2) && Math.Pow(offset.X - rect.Right, 2) + Math.Pow(offset.Y - rect.Y, 2) > Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else if (offset.X > rect.Right && offset.Y > rect.Bottom)
         {
             if (Math.Pow(offset.X - rect.Right, 2) + Math.Pow(offset.Y - rect.Bottom, 2) < Math.Pow(radius, 2) && Math.Pow(offset.X - rect.X, 2) + Math.Pow(offset.Y - rect.Y, 2) > Math.Pow(radius, 2))
             {
                 return(true);
             }
             else
             {
                 return(false);
             }
         }
         else
         {
             if (2 * radius >= Math.Sqrt(Math.Pow(rect.Width, 2) + Math.Pow(rect.Height, 2)))
             {
                 if (((offset.X >= rect.X - radius && offset.X <= rect.Right + radius) && (offset.Y >= rect.Y - radius && offset.Y <= rect.Bottom + radius)) && !((offset.X >= rect.Right - Constant.HalfSqrt2 * radius && offset.X <= rect.X + Constant.HalfSqrt2 * radius) && (offset.Y >= rect.Bottom - Constant.HalfSqrt2 * radius && offset.Y <= rect.Y + Constant.HalfSqrt2 * radius)))
                 {
                     return(true);
                 }
                 else
                 {
                     return(false);
                 }
             }
             else
             {
                 if (offset.X >= rect.X - radius && offset.X <= rect.Right + radius && offset.Y >= rect.Y - radius && offset.Y <= rect.Bottom + radius)
                 {
                     return(true);
                 }
                 else
                 {
                     return(false);
                 }
             }
         }
     }
 }
Beispiel #19
0
        private static readonly PointD3D _NormalVectorPZX = new PointD3D(0, 1, 0);  // 正方体表面的 +ZX 法向量。

        //

        /// <summary>
        /// 绘制一个长方体,并返回表示是否已经实际完成绘图的布尔值。
        /// </summary>
        /// <param name="bmp">用于绘制的位图。</param>
        /// <param name="center">长方体的中心坐标。</param>
        /// <param name="size">长方体的大小。</param>
        /// <param name="color">长方体的颜色。</param>
        /// <param name="edgeWidth">长方体的棱的宽度。</param>
        /// <param name="affineMatrices">仿射矩阵(左矩阵)列表。</param>
        /// <param name="focalLength">焦距。</param>
        /// <param name="illuminationDirection">光照方向。</param>
        /// <param name="illuminationDirectionIsAfterAffineTransform">光照方向是否基于仿射变换之后的坐标系。</param>
        /// <param name="exposure">曝光,取值范围为 [-100, 100]。</param>
        /// <param name="antiAlias">是否使用抗锯齿模式绘图。</param>
        /// <returns>布尔值,表示是否已经实际完成绘图。</returns>
        public static bool PaintCuboid(Bitmap bmp, PointD3D center, PointD3D size, Color color, float edgeWidth, List <Matrix> affineMatrices, double focalLength, PointD3D illuminationDirection, bool illuminationDirectionIsAfterAffineTransform, double exposure, bool antiAlias)
        {
            try
            {
                if (bmp is null || center.IsNaNOrInfinity || (size.IsNaNOrInfinity || size.IsZero) || (color.IsEmpty || color.A == 0) || InternalMethod.IsNaNOrInfinity(edgeWidth) || InternalMethod.IsNullOrEmpty(affineMatrices) || (InternalMethod.IsNaNOrInfinity(focalLength) || focalLength < 0) || illuminationDirection.IsNaNOrInfinity || InternalMethod.IsNaNOrInfinity(exposure))
                {
                    return(false);
                }
                else
                {
                    PointD3D P3D_000 = _Vertex000;
                    PointD3D P3D_100 = _Vertex100;
                    PointD3D P3D_010 = _Vertex010;
                    PointD3D P3D_110 = _Vertex110;
                    PointD3D P3D_001 = _Vertex001;
                    PointD3D P3D_101 = _Vertex101;
                    PointD3D P3D_011 = _Vertex011;
                    PointD3D P3D_111 = _Vertex111;

                    P3D_000.Scale(size);
                    P3D_100.Scale(size);
                    P3D_010.Scale(size);
                    P3D_110.Scale(size);
                    P3D_001.Scale(size);
                    P3D_101.Scale(size);
                    P3D_011.Scale(size);
                    P3D_111.Scale(size);

                    P3D_000.Offset(center);
                    P3D_100.Offset(center);
                    P3D_010.Offset(center);
                    P3D_110.Offset(center);
                    P3D_001.Offset(center);
                    P3D_101.Offset(center);
                    P3D_011.Offset(center);
                    P3D_111.Offset(center);

                    P3D_000.AffineTransform(affineMatrices);
                    P3D_100.AffineTransform(affineMatrices);
                    P3D_010.AffineTransform(affineMatrices);
                    P3D_110.AffineTransform(affineMatrices);
                    P3D_001.AffineTransform(affineMatrices);
                    P3D_101.AffineTransform(affineMatrices);
                    P3D_011.AffineTransform(affineMatrices);
                    P3D_111.AffineTransform(affineMatrices);

                    PointD3D PrjCenter = new PointD3D(bmp.Width / 2, bmp.Height / 2, 0);

                    PointD P2D_000 = P3D_000.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_100 = P3D_100.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_010 = P3D_010.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_110 = P3D_110.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_001 = P3D_001.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_101 = P3D_101.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_011 = P3D_011.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_111 = P3D_111.ProjectToXY(PrjCenter, focalLength);

                    PointF P_000 = P2D_000.ToPointF();
                    PointF P_100 = P2D_100.ToPointF();
                    PointF P_010 = P2D_010.ToPointF();
                    PointF P_110 = P2D_110.ToPointF();
                    PointF P_001 = P2D_001.ToPointF();
                    PointF P_101 = P2D_101.ToPointF();
                    PointF P_011 = P2D_011.ToPointF();
                    PointF P_111 = P2D_111.ToPointF();

                    PointD3D[][] Element3D = new PointD3D[][]
                    {
                        // XY 面
                        new PointD3D[] { P3D_000, P3D_010, P3D_110, P3D_100 },
                        new PointD3D[] { P3D_001, P3D_011, P3D_111, P3D_101 },

                        // YZ 面
                        new PointD3D[] { P3D_000, P3D_001, P3D_011, P3D_010 },
                        new PointD3D[] { P3D_100, P3D_101, P3D_111, P3D_110 },

                        // ZX 面
                        new PointD3D[] { P3D_000, P3D_001, P3D_101, P3D_100 },
                        new PointD3D[] { P3D_010, P3D_011, P3D_111, P3D_110 },

                        // X 棱
                        new PointD3D[] { P3D_000, P3D_100 },
                        new PointD3D[] { P3D_010, P3D_110 },
                        new PointD3D[] { P3D_001, P3D_101 },
                        new PointD3D[] { P3D_011, P3D_111 },

                        // Y 棱
                        new PointD3D[] { P3D_000, P3D_010 },
                        new PointD3D[] { P3D_100, P3D_110 },
                        new PointD3D[] { P3D_001, P3D_011 },
                        new PointD3D[] { P3D_101, P3D_111 },

                        // Z 棱
                        new PointD3D[] { P3D_000, P3D_001 },
                        new PointD3D[] { P3D_100, P3D_101 },
                        new PointD3D[] { P3D_010, P3D_011 },
                        new PointD3D[] { P3D_110, P3D_111 }
                    };

                    PointF[][] Element2D = new PointF[][]
                    {
                        // XY 面
                        new PointF[] { P_000, P_010, P_110, P_100 },
                        new PointF[] { P_001, P_011, P_111, P_101 },

                        // YZ 面
                        new PointF[] { P_000, P_001, P_011, P_010 },
                        new PointF[] { P_100, P_101, P_111, P_110 },

                        // ZX 面
                        new PointF[] { P_000, P_001, P_101, P_100 },
                        new PointF[] { P_010, P_011, P_111, P_110 },

                        // X 棱
                        new PointF[] { P_000, P_100 },
                        new PointF[] { P_010, P_110 },
                        new PointF[] { P_001, P_101 },
                        new PointF[] { P_011, P_111 },

                        // Y 棱
                        new PointF[] { P_000, P_010 },
                        new PointF[] { P_100, P_110 },
                        new PointF[] { P_001, P_011 },
                        new PointF[] { P_101, P_111 },

                        // Z 棱
                        new PointF[] { P_000, P_001 },
                        new PointF[] { P_100, P_101 },
                        new PointF[] { P_010, P_011 },
                        new PointF[] { P_110, P_111 }
                    };

                    //

                    bool CuboidIsVisible = false;

                    bool[] ElementVisible = new bool[Element2D.Length];

                    for (int i = 0; i < Element2D.Length; i++)
                    {
                        bool EVisible = false;

                        foreach (PointF P in Element2D[i])
                        {
                            PointD P2D = P;

                            if (P2D.IsNaNOrInfinity)
                            {
                                EVisible = false;

                                break;
                            }
                            else
                            {
                                if (Geometry.PointIsVisibleInRectangle(P2D, new RectangleF(new Point(0, 0), bmp.Size)))
                                {
                                    EVisible = true;
                                }
                            }
                        }

                        ElementVisible[i] = EVisible;

                        if (!CuboidIsVisible && EVisible)
                        {
                            CuboidIsVisible = true;
                        }
                    }

                    if (!CuboidIsVisible)
                    {
                        return(false);
                    }
                    else
                    {
                        double[] IlluminationIntensity = new double[Element3D.Length];

                        double Exposure = Math.Max(-2, Math.Min(exposure / 50, 2));

                        if (illuminationDirection.IsZero)
                        {
                            for (int i = 0; i < 6; i++)
                            {
                                IlluminationIntensity[i] = Exposure;
                            }

                            for (int i = 6; i < Element3D.Length; i++)
                            {
                                IlluminationIntensity[i] = Constant.HalfSqrt2 * (Exposure + 1) + (Exposure - 1);
                            }
                        }
                        else
                        {
                            PointD3D[] NormalVector = new PointD3D[]
                            {
                                // XY 面
                                _NormalVectorNXY,
                                _NormalVectorPXY,

                                // YZ 面
                                _NormalVectorNYZ,
                                _NormalVectorPYZ,

                                // ZX 面
                                _NormalVectorNZX,
                                _NormalVectorPZX
                            };

                            if (illuminationDirectionIsAfterAffineTransform)
                            {
                                PointD3D NewOriginOpposite = PointD3D.Zero.AffineTransformCopy(affineMatrices).Opposite;

                                for (int i = 0; i < NormalVector.Length; i++)
                                {
                                    NormalVector[i].AffineTransform(affineMatrices);
                                    NormalVector[i].Offset(NewOriginOpposite);
                                }
                            }

                            double[] Angle = new double[NormalVector.Length];

                            for (int i = 0; i < NormalVector.Length; i++)
                            {
                                Angle[i] = illuminationDirection.AngleFrom(NormalVector[i]);
                            }

                            for (int i = 0; i < Angle.Length; i++)
                            {
                                double A       = Angle[i];
                                double CosA    = Math.Cos(A);
                                double CosSqrA = CosA * CosA;

                                double _IlluminationIntensity = (A < Constant.HalfPi ? -CosSqrA : (A > Constant.HalfPi ? CosSqrA : 0));

                                if (color.A < 255 && A != Constant.HalfPi)
                                {
                                    double Transmittance = 1 - (double)color.A / 255;

                                    if (A < Constant.HalfPi)
                                    {
                                        _IlluminationIntensity += (Transmittance * Math.Abs(CosA) * CosSqrA);
                                    }
                                    else
                                    {
                                        _IlluminationIntensity -= ((1 - Transmittance) * (1 - Math.Abs(CosA)) * CosSqrA);
                                    }
                                }

                                _IlluminationIntensity += Exposure;

                                IlluminationIntensity[i] = _IlluminationIntensity;
                            }

                            for (int i = 6; i < Element3D.Length; i++)
                            {
                                double _IlluminationIntensity = 0;

                                int Num = 0;

                                for (int j = 0; j < 6; j++)
                                {
                                    bool Flag = true;

                                    foreach (PointD3D P in Element3D[i])
                                    {
                                        if (!Element3D[j].Contains(P))
                                        {
                                            Flag = false;

                                            break;
                                        }
                                    }

                                    if (Flag)
                                    {
                                        _IlluminationIntensity += IlluminationIntensity[j];

                                        Num++;
                                    }
                                }

                                _IlluminationIntensity = Constant.HalfSqrt2 * (_IlluminationIntensity / Num + 1) + (Exposure - 1);

                                IlluminationIntensity[i] = _IlluminationIntensity;
                            }
                        }

                        for (int i = 0; i < IlluminationIntensity.Length; i++)
                        {
                            IlluminationIntensity[i] = Math.Max(-1, Math.Min(IlluminationIntensity[i], 1));
                        }

                        //

                        Color[] ElementColor = new Color[IlluminationIntensity.Length];

                        for (int i = 0; i < IlluminationIntensity.Length; i++)
                        {
                            double _IlluminationIntensity = IlluminationIntensity[i];

                            if (_IlluminationIntensity == 0)
                            {
                                ElementColor[i] = color;
                            }
                            else
                            {
                                ColorX EColor = color;

                                if (_IlluminationIntensity < 0)
                                {
                                    EColor.Lightness_HSL += EColor.Lightness_HSL * _IlluminationIntensity;
                                }
                                else
                                {
                                    EColor.Lightness_HSL += (100 - EColor.Lightness_HSL) * _IlluminationIntensity;
                                }

                                ElementColor[i] = EColor.ToColor();
                            }
                        }

                        //

                        double[] ElementZAvg = new double[Element3D.Length];

                        for (int i = 0; i < Element3D.Length; i++)
                        {
                            PointD3D[] Element = Element3D[i];

                            double ZAvg = 0;

                            foreach (PointD3D P in Element)
                            {
                                ZAvg += P.Z;
                            }

                            ZAvg /= Element.Length;

                            ElementZAvg[i] = ZAvg;
                        }

                        int[] ElementIndex = new int[ElementZAvg.Length];

                        for (int i = 0; i < ElementZAvg.Length; i++)
                        {
                            ElementIndex[i] = i;
                        }

                        for (int i = 0; i < ElementZAvg.Length; i++)
                        {
                            for (int j = i + 1; j < ElementZAvg.Length; j++)
                            {
                                if (ElementZAvg[ElementIndex[i]] < ElementZAvg[ElementIndex[j]] || (ElementZAvg[ElementIndex[i]] <= ElementZAvg[ElementIndex[j]] + edgeWidth && Element2D[ElementIndex[i]].Length < Element2D[ElementIndex[j]].Length))
                                {
                                    int Temp = ElementIndex[i];
                                    ElementIndex[i] = ElementIndex[j];
                                    ElementIndex[j] = Temp;
                                }
                            }
                        }

                        //

                        using (Graphics Grph = Graphics.FromImage(bmp))
                        {
                            if (antiAlias)
                            {
                                Grph.SmoothingMode = SmoothingMode.AntiAlias;
                            }

                            //

                            for (int i = 0; i < ElementIndex.Length; i++)
                            {
                                int EIndex = ElementIndex[i];

                                if (ElementVisible[EIndex])
                                {
                                    Color EColor = ElementColor[EIndex];

                                    if (!EColor.IsEmpty && EColor.A > 0)
                                    {
                                        PointF[] Element = Element2D[EIndex];

                                        if (Element.Length >= 3)
                                        {
                                            try
                                            {
                                                using (SolidBrush Br = new SolidBrush(EColor))
                                                {
                                                    Grph.FillPolygon(Br, Element);
                                                }
                                            }
                                            catch { }
                                        }
                                        else if (Element.Length == 2)
                                        {
                                            if (edgeWidth > 0)
                                            {
                                                float EdgeWidth = (focalLength == 0 ? edgeWidth : (float)(focalLength / (ElementZAvg[EIndex] - PrjCenter.Z) * edgeWidth));

                                                try
                                                {
                                                    Brush Br;

                                                    Func <Color, double, int> GetAlpha = (Cr, Z) =>
                                                    {
                                                        int Alpha;

                                                        if (focalLength == 0)
                                                        {
                                                            Alpha = Cr.A;
                                                        }
                                                        else
                                                        {
                                                            if (Z - PrjCenter.Z <= focalLength)
                                                            {
                                                                Alpha = Cr.A;
                                                            }
                                                            else
                                                            {
                                                                Alpha = (int)Math.Max(0, Math.Min(focalLength / (Z - PrjCenter.Z) * Cr.A, 255));
                                                            }
                                                        }

                                                        if (EdgeWidth < 1)
                                                        {
                                                            Alpha = (int)(Alpha * EdgeWidth);
                                                        }

                                                        return(Alpha);
                                                    };

                                                    if (((PointD)Element[0]).DistanceFrom(Element[1]) > 1)
                                                    {
                                                        int Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].Z), Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].Z);

                                                        Br = new LinearGradientBrush(Element[0], Element[1], Color.FromArgb(Alpha0, EColor), Color.FromArgb(Alpha1, EColor));
                                                    }
                                                    else
                                                    {
                                                        int Alpha = GetAlpha(EColor, ElementZAvg[EIndex]);

                                                        Br = new SolidBrush(Color.FromArgb(Alpha, EColor));
                                                    }

                                                    using (Pen Pn = new Pen(Br, EdgeWidth))
                                                    {
                                                        Grph.DrawLines(Pn, Element);
                                                    }

                                                    if (!(Br is null))
                                                    {
                                                        Br.Dispose();
                                                    }
                                                }
                                                catch { }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        //

                        return(true);
                    }
                }
            }
Beispiel #20
0
        private const string _NegativeMagnitudeOrderCode = "mμnpfazy"; // 千进制负数量级符号。

        /// <summary>
        /// 返回一个以科学记数法表示数值的字符串。
        /// </summary>
        /// <param name="value">数值。</param>
        /// <param name="significance">有效数字位数,0 表示保留所有有效数字。</param>
        /// <param name="useNaturalExpression">是否使用 "m×10^n" 的格式,而不是 "mE+n"。</param>
        /// <param name="useMagnitudeOrderCode">对于数量级介于 ±24 的数值,是否使用千进制数量级符号。</param>
        /// <param name="unit">单位。</param>
        /// <returns>字符串,表示以科学记数法表示的数值。</returns>
        public static string GetScientificNotationString(double value, int significance, bool useNaturalExpression, bool useMagnitudeOrderCode, string unit)
        {
            if (InternalMethod.IsNaNOrInfinity(value))
            {
                return("N/A");
            }
            else
            {
                string part1 = string.Empty, part2 = string.Empty, part3 = string.Empty, part4 = string.Empty;

                if (value == 0 || (value > -1E-308 && value < 1E-308))
                {
                    part2 = "0";
                    part4 = (string.IsNullOrEmpty(unit) ? string.Empty : " " + unit);
                }
                else
                {
                    int sign = Math.Sign(value);

                    part1 = (sign < 0 ? "-" : string.Empty);

                    value = Math.Abs(value);

                    significance = Math.Max(0, Math.Min(significance, 16));

                    int exp = (int)Math.Floor(Math.Log10(value));

                    if (significance > 0)
                    {
                        exp -= (significance - 1);

                        value = Math.Round(value / Math.Pow(10, exp));
                    }
                    else
                    {
                        value /= Math.Pow(10, exp);
                    }

                    while (value >= 10)
                    {
                        value /= 10;
                        exp++;
                    }

                    if (useMagnitudeOrderCode)
                    {
                        if (exp >= -24 && exp < 27)
                        {
                            int mod = 0;

                            if (exp >= 0)
                            {
                                mod = exp % 3;
                            }
                            else
                            {
                                mod = (-exp) % 3;

                                if (mod > 0)
                                {
                                    mod = 3 - mod;
                                }
                            }

                            if (mod > 0)
                            {
                                value *= Math.Pow(10, mod);
                            }

                            part2 = (significance > 0 ? value.ToString("N" + Math.Max(0, significance - 1 - mod)) : value.ToString());

                            int mag = 0;

                            if (exp >= 0)
                            {
                                mag = exp / 3;
                            }
                            else
                            {
                                mag = (exp + 1) / 3 - 1;
                            }

                            string magCode = (mag > 0 ? _PositiveMagnitudeOrderCode[mag - 1].ToString() : (mag < 0 ? _NegativeMagnitudeOrderCode[-mag - 1].ToString() : string.Empty));

                            if (string.IsNullOrEmpty(unit))
                            {
                                part3 = magCode;
                                part4 = string.Empty;
                            }
                            else
                            {
                                part3 = " " + magCode;
                                part4 = unit;
                            }
                        }
                        else
                        {
                            part2 = (significance > 0 ? value.ToString("N" + Math.Max(0, significance - 1)) : value.ToString());
                            part3 = (useNaturalExpression ? "×10^" + exp : (exp > 0 ? "E+" + exp : "E" + exp));
                            part4 = (string.IsNullOrEmpty(unit) ? string.Empty : " " + unit);
                        }
                    }
                    else
                    {
                        part2 = (significance > 0 ? value.ToString("N" + Math.Max(0, significance - 1)) : value.ToString());
                        part3 = (exp == 0 ? string.Empty : (useNaturalExpression ? "×10^" + exp : (exp > 0 ? "E+" + exp : "E" + exp)));
                        part4 = (string.IsNullOrEmpty(unit) ? string.Empty : " " + unit);
                    }
                }

                return(string.Concat(part1, part2, part3, part4));
            }
        }