/// <summary> /// This method creates gradien color with brightnes. /// </summary> /// <param name="beginColor">Start color for gradient.</param> /// <param name="position">Position used between Start and end color.</param> /// <returns>Calculated Gradient color from gradient position</returns> private Color GetBrightGradientColor(Color beginColor, double position) { position = position * 2; double brightness = 0.5; if (position < brightness) { return(ChartGraphics.GetGradientColor(Color.FromArgb(beginColor.A, 255, 255, 255), beginColor, 1 - brightness + position)); } else if (-brightness + position < 1) { return(ChartGraphics.GetGradientColor(beginColor, Color.Black, -brightness + position)); } else { return(Color.FromArgb(beginColor.A, 0, 0, 0)); } }
/// <summary> /// Return intensity of lightStyle for Polygons. There are tree types of lights: None, /// Simplistic and Realistic. None Style have same lightStyle intensity on /// all polygons. Normal vector doesn’t have influence on this type /// of lighting. Simplistic style have lightStyle source, which is /// rotated together with scene. Realistic lighting have fixed lightStyle /// source and intensity of lightStyle is change when scene is rotated. /// </summary> /// <param name="points">Points of the polygon</param> /// <param name="surfaceColor">Color used for polygons without lighting</param> /// <param name="visiblePolygon">This flag gets information if polygon is visible or not.</param> /// <param name="rotation">Y angle ( from -90 to 90 ) Should be used width switchSeriesOrder to get from -180 to 180</param> /// <param name="surfaceName">Used for lighting of front - back and left - right sides</param> /// <param name="switchSeriesOrder">Used to calculate real y angle</param> /// <returns>Color corrected with intensity of lightStyle</returns> internal Color GetPolygonLight(Point3D[] points, Color surfaceColor, bool visiblePolygon, float rotation, SurfaceNames surfaceName, bool switchSeriesOrder) { // Corrected color Color color = surfaceColor; // Direction of lightStyle source Point3D lightSource; lightSource = new Point3D(0F, 0F, 1F); // There are tree different lightStyle styles: None, Simplistic and realistic. switch (_lightStyle) { // LightStyle style is None case LightStyle.None: { // Use same color break; } // LightStyle style is Simplistic case LightStyle.Simplistic: { // Find two vectors of polygon Point3D firstVector = new Point3D(); firstVector.X = points[0].X - points[1].X; firstVector.Y = points[0].Y - points[1].Y; firstVector.Z = points[0].Z - points[1].Z; Point3D secondVector = new Point3D(); secondVector.X = points[2].X - points[1].X; secondVector.Y = points[2].Y - points[1].Y; secondVector.Z = points[2].Z - points[1].Z; // Find Normal vector for Polygon Point3D normalVector = new Point3D(); normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y; normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z; normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X; // Polygon is left side ( like side of area chart ) if (surfaceName == SurfaceNames.Left) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); } // Polygon is right side ( like side of area chart ) else if (surfaceName == SurfaceNames.Right) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); } // Polygon is front side ( like side of area chart ) else if (surfaceName == SurfaceNames.Front) { color = surfaceColor; } // Polygon is back side ( like side of area chart ) else if (surfaceName == SurfaceNames.Back) { color = surfaceColor; } // Polygon has angle with bottom side ( Line chart or top of area chart ) else { float angleLeft; float angleRight; // Find angles between lightStyle and polygon for different y-axis angles. if (switchSeriesOrder) { if (rotation > 0 && rotation <= 90) { angleLeft = GetAngle(normalVector, _lightVectors[3]); angleRight = GetAngle(normalVector, _lightVectors[4]); } else { angleLeft = GetAngle(normalVector, _lightVectors[4]); angleRight = GetAngle(normalVector, _lightVectors[3]); } } else { if (rotation > 0 && rotation <= 90) { angleLeft = GetAngle(normalVector, _lightVectors[4]); angleRight = GetAngle(normalVector, _lightVectors[3]); } else { angleLeft = GetAngle(normalVector, _lightVectors[3]); angleRight = GetAngle(normalVector, _lightVectors[4]); } } if (Math.Abs(angleLeft - angleRight) < 0.01) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); } else if (angleLeft < angleRight) { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); } else { color = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); } } break; } // LightStyle style is Realistic default: { // Find two vectors of polygon Point3D firstVector = new Point3D(); firstVector.X = points[0].X - points[1].X; firstVector.Y = points[0].Y - points[1].Y; firstVector.Z = points[0].Z - points[1].Z; Point3D secondVector = new Point3D(); secondVector.X = points[2].X - points[1].X; secondVector.Y = points[2].Y - points[1].Y; secondVector.Z = points[2].Z - points[1].Z; // Find Normal vector for Polygon Point3D normalVector = new Point3D(); normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y; normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z; normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X; // ****************************************************************** // Color correction. Angle between Normal vector of polygon and // vector of lightStyle source is used. // ****************************************************************** if (surfaceName == SurfaceNames.Front) { lightSource.Z *= -1; color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[2]) / Math.PI); } else if (surfaceName == SurfaceNames.Back) { lightSource.Z *= -1; color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[1]) / Math.PI); } else { if (visiblePolygon) { lightSource.Z *= -1; } color = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, normalVector) / Math.PI); } break; } } return(color); }
/// <summary> /// Return intensity of lightStyle for 3D Cube. There are tree types of lights: None, /// Simplistic and Realistic. None Style have same lightStyle intensity on /// all polygons. Normal vector doesn’t have influence on this type /// of lighting. Simplistic style have lightStyle source, which is /// rotated together with scene. Realistic lighting have fixed lightStyle /// source and intensity of lightStyle is change when scene is rotated. /// </summary> /// <param name="surfaceColor">Color used for polygons without lighting</param> /// <param name="front">Color corrected with intensity of lightStyle for Front side of the 3D Rectangle</param> /// <param name="back">Color corrected with intensity of lightStyle for Back side of the 3D Rectangle</param> /// <param name="left">Color corrected with intensity of lightStyle for Left side of the 3D Rectangle</param> /// <param name="right">Color corrected with intensity of lightStyle for Right side of the 3D Rectangle</param> /// <param name="top">Color corrected with intensity of lightStyle for Top side of the 3D Rectangle</param> /// <param name="bottom">Color corrected with intensity of lightStyle for Bottom side of the 3D Rectangle</param> internal void GetLight(Color surfaceColor, out Color front, out Color back, out Color left, out Color right, out Color top, out Color bottom) { switch (_lightStyle) { // LightStyle style is None case LightStyle.None: { front = surfaceColor; left = surfaceColor; top = surfaceColor; back = surfaceColor; right = surfaceColor; bottom = surfaceColor; break; } // LightStyle style is Simplistic case LightStyle.Simplistic: { front = surfaceColor; left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); top = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); back = surfaceColor; right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25); bottom = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15); break; } // LightStyle style is Realistic default: { // For Right Axis angle Realistic lightStyle should be different if (_rightAngleAxis) { // LightStyle source Vector Point3D lightSource = new Point3D(0F, 0F, -1F); Point3D [] rightPRpoints = new Point3D[1]; rightPRpoints[0] = lightSource; RightAngleProjection(rightPRpoints); // ****************************************************************** // Color correction. Angle between Normal vector of polygon and // vector of lightStyle source is used. // ****************************************************************** if (this._angleY >= 45 || this._angleY <= -45) { front = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[1]) / Math.PI); back = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[2]) / Math.PI); left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0); right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0); } else { front = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0); back = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 1); left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[3]) / Math.PI); right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[4]) / Math.PI); } top = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[5]) / Math.PI); bottom = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, GetAngle(lightSource, _lightVectors[6]) / Math.PI); } else { // LightStyle source Vector Point3D lightSource = new Point3D(0F, 0F, 1F); // ****************************************************************** // Color correction. Angle between Normal vector of polygon and // vector of lightStyle source is used. // ****************************************************************** front = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[1]) / Math.PI); back = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[2]) / Math.PI); left = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[3]) / Math.PI); right = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[4]) / Math.PI); top = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[5]) / Math.PI); bottom = GetBrightGradientColor(surfaceColor, GetAngle(lightSource, _lightVectors[6]) / Math.PI); } break; } } }
/// <summary> /// Draws text in specified rectangle. /// </summary> /// <param name="graphics">Chart graphics.</param> /// <param name="textPosition">Text position.</param> /// <param name="noSpacingForCenteredText">True if text allowed to be outside of position when centered.</param> /// <param name="getTextPosition">True if position text must be returned by the method.</param> /// <returns>Text actual position if required.</returns> internal RectangleF DrawText(ChartGraphics graphics, RectangleF textPosition, bool noSpacingForCenteredText, bool getTextPosition) { RectangleF textActualPosition = RectangleF.Empty; //*************************************************************** //** Adjust text position uing text spacing //*************************************************************** bool annotationRelative = false; RectangleF textSpacing = GetTextSpacing(out annotationRelative); float spacingScaleX = 1f; float spacingScaleY = 1f; if (annotationRelative) { if (textPosition.Width > 25f) { spacingScaleX = textPosition.Width / 50f; spacingScaleX = Math.Max(1f, spacingScaleX); } if (textPosition.Height > 25f) { spacingScaleY = textPosition.Height / 50f; spacingScaleY = Math.Max(1f, spacingScaleY); } } RectangleF textPositionWithSpacing = new RectangleF(textPosition.Location, textPosition.Size); textPositionWithSpacing.Width -= (textSpacing.Width + textSpacing.X) * spacingScaleX; textPositionWithSpacing.X += textSpacing.X * spacingScaleX; textPositionWithSpacing.Height -= (textSpacing.Height + textSpacing.Y) * spacingScaleY; textPositionWithSpacing.Y += textSpacing.Y * spacingScaleY; //*************************************************************** //** Replace new line characters //*************************************************************** string titleText = this.ReplaceKeywords(this.Text.Replace("\\n", "\n")); //*************************************************************** //** Check if centered text require spacing. //** Use only half of the spacing required. //** Apply only for 1 line of text. //*************************************************************** if (noSpacingForCenteredText && titleText.IndexOf('\n') == -1) { if (this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { textPositionWithSpacing.Y = textPosition.Y; textPositionWithSpacing.Height = textPosition.Height; textPositionWithSpacing.Height -= textSpacing.Height / 2f + textSpacing.Y / 2f; textPositionWithSpacing.Y += textSpacing.Y / 2f; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { textPositionWithSpacing.X = textPosition.X; textPositionWithSpacing.Width = textPosition.Width; textPositionWithSpacing.Width -= textSpacing.Width / 2f + textSpacing.X / 2f; textPositionWithSpacing.X += textSpacing.X / 2f; } } // Draw text using (Brush textBrush = new SolidBrush(this.ForeColor)) { using (StringFormat format = new StringFormat(StringFormat.GenericTypographic)) { //*************************************************************** //** Set text format //*************************************************************** format.FormatFlags = format.FormatFlags ^ StringFormatFlags.LineLimit; format.Trimming = StringTrimming.EllipsisCharacter; if (this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight) { format.Alignment = StringAlignment.Far; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { format.Alignment = StringAlignment.Center; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.BottomRight) { format.LineAlignment = StringAlignment.Far; } if (this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { format.LineAlignment = StringAlignment.Center; } //*************************************************************** //** Set shadow color and offset //*************************************************************** Color textShadowColor = ChartGraphics.GetGradientColor(this.ForeColor, Color.Black, 0.8); int textShadowOffset = 1; TextStyle textStyle = this.TextStyle; if (textStyle == TextStyle.Shadow && ShadowOffset != 0) { // Draw shadowed text textShadowColor = ShadowColor; textShadowOffset = ShadowOffset; } if (textStyle == TextStyle.Shadow) { textShadowColor = (textShadowColor.A != 255) ? textShadowColor : Color.FromArgb(textShadowColor.A / 2, textShadowColor); } //*************************************************************** //** Get text actual position //*************************************************************** if (getTextPosition) { // Measure text size SizeF textSize = graphics.MeasureStringRel( this.ReplaceKeywords(_text.Replace("\\n", "\n")), this.Font, textPositionWithSpacing.Size, format); // Get text position textActualPosition = new RectangleF(textPositionWithSpacing.Location, textSize); if (this.Alignment == ContentAlignment.BottomRight || this.Alignment == ContentAlignment.MiddleRight || this.Alignment == ContentAlignment.TopRight) { textActualPosition.X += textPositionWithSpacing.Width - textSize.Width; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.TopCenter) { textActualPosition.X += (textPositionWithSpacing.Width - textSize.Width) / 2f; } if (this.Alignment == ContentAlignment.BottomCenter || this.Alignment == ContentAlignment.BottomLeft || this.Alignment == ContentAlignment.BottomRight) { textActualPosition.Y += textPositionWithSpacing.Height - textSize.Height; } if (this.Alignment == ContentAlignment.MiddleCenter || this.Alignment == ContentAlignment.MiddleLeft || this.Alignment == ContentAlignment.MiddleRight) { textActualPosition.Y += (textPositionWithSpacing.Height - textSize.Height) / 2f; } // Do not allow text to go outside annotation position textActualPosition.Intersect(textPositionWithSpacing); } RectangleF absPosition = graphics.GetAbsoluteRectangle(textPositionWithSpacing); Title.DrawStringWithStyle( graphics, titleText, this.TextStyle, this.Font, absPosition, this.ForeColor, textShadowColor, textShadowOffset, format, TextOrientation.Auto ); } } return(textActualPosition); }