Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //-------------------------------------------------------------
- // <copyright company=’Microsoft Corporation’>
- // Copyright © Microsoft Corporation. All Rights Reserved.
- // </copyright>
- //-------------------------------------------------------------
- // @owner=alexgor, deliant
- //=================================================================
- // File: Matrix3D.cs
- //
- // Namespace: DataVisualization.Charting
- //
- // Classes: Matrix3D
- //
- // Purpose: Matrix3D class is used during the 3D drawings to
- // transform plotting area 3D coordinates into the 2D
- // projection coordinates based on rotation and
- // perspective settings.
- //
- // Reviewed: AG - Dec 4, 2002
- // AG - Microsoft 14, 2007
- //
- //===================================================================
- #region Used namespaces
- using System;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Text;
- using System.Drawing.Imaging;
- using System.ComponentModel;
- using System.Collections;
- #if Microsoft_CONTROL
- using System.Windows.Forms.DataVisualization.Charting;
- using System.Windows.Forms.DataVisualization.Charting.Data;
- using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
- using System.Windows.Forms.DataVisualization.Charting.Utilities;
- using System.Windows.Forms.DataVisualization.Charting.Borders3D;
- #else
- //using System.Web.UI.DataVisualization.Charting.Utilities;
- //using System.Web.UI.DataVisualization.Charting.Borders3D;
- #endif
- #endregion
- #if Microsoft_CONTROL
- namespace System.Windows.Forms.DataVisualization.Charting
- #else
- namespace System.Web.UI.DataVisualization.Charting
- #endif
- {
- /// <summary>
- /// This class is responsible for all 3D coordinates transformations: Translation,
- /// Rotation, Scale, Perspective and RightAngle Projection. Translation
- /// and rotation are stored in composite matrix (mainMatrix), and scaling,
- /// projection and non-composite translation are stored in private fields.
- /// Matrix is initialized with Chart Area 3D cube, which is invisible boundary
- /// cube of 3D Chart area. The matrix has to be initialized every time
- /// when angles, position or perspective parameters are changed. Method
- /// TransformPoints will apply 3D Transformation on points using
- /// Initialization values: Main matrix and other initialization values.
- /// </summary>
- internal class Matrix3D
- {
- #region Enumerations
- /// <summary>
- /// 3D Axis used for rotation
- /// </summary>
- private enum RotationAxis
- {
- /// <summary>
- /// Rotation around X axis.
- /// </summary>
- X,
- /// <summary>
- /// Rotation around Y axis.
- /// </summary>
- Y,
- /// <summary>
- /// Rotation around Z axis.
- /// </summary>
- Z
- }
- #endregion // Enumerations
- #region Fields
- /// <summary>
- /// Composite matrix.
- /// </summary>
- private float [][] _mainMatrix;
- /// <summary>
- /// Default translation for chart area cube ( without composition ).
- /// </summary>
- private float _translateX;
- /// <summary>
- /// Default translation for chart area cube ( without composition ).
- /// </summary>
- private float _translateY;
- /// <summary>
- /// Default translation for chart area cube ( without composition ).
- /// </summary>
- private float _translateZ;
- /// <summary>
- /// The value, which is used to rescale chart area.
- /// </summary>
- private float _scale;
- /// <summary>
- /// The value used for Isometric Shift.
- /// </summary>
- private float _shiftX;
- /// <summary>
- /// The value used for Isometric Shift.
- /// </summary>
- private float _shiftY;
- /// <summary>
- /// Perspective value.
- /// </summary>
- internal float _perspective;
- /// <summary>
- /// Isometric projection.
- /// </summary>
- private bool _rightAngleAxis;
- /// <summary>
- /// The value, which is used for perspective.
- /// </summary>
- private float _perspectiveFactor = float.NaN;
- /// <summary>
- /// The value, which is used to set projection plane.
- /// </summary>
- private float _perspectiveZ;
- /// <summary>
- /// X Angle.
- /// </summary>
- private float _angleX;
- /// <summary>
- /// Y Angle.
- /// </summary>
- private float _angleY;
- /// <summary>
- /// Private fields used for lighting
- /// </summary>
- Point3D [] _lightVectors = new Point3D[7];
- /// <summary>
- /// LightStyle Style
- /// </summary>
- LightStyle _lightStyle;
- #endregion // Fields
- #region Properties
- /// <summary>
- /// Gets the X Angle.
- /// </summary>
- internal float AngleX
- {
- get { return _angleX; }
- }
- /// <summary>
- /// Gets the Y Angle.
- /// </summary>
- internal float AngleY
- {
- get { return _angleY; }
- }
- /// <summary>
- /// Get perspective value.
- /// </summary>
- internal float Perspective
- {
- get { return _perspective; }
- }
- #endregion // Properties
- #region Internal and Public Methods
- /// <summary>
- /// Constructor for Matrix 3D
- /// </summary>
- public Matrix3D()
- {
- }
- /// <summary>
- /// Checks if 3D matrix was initialized.
- /// </summary>
- /// <returns>True if matrix was initialized.</returns>
- public bool IsInitialized()
- {
- return (this._mainMatrix != null);
- }
- /// <summary>
- /// Initialize Matrix 3D. This method calculates how much a chart area
- /// cube has to be resized to fit Inner Plotting Area rectangle. Order
- /// of operation is following: Translation for X and Y axes, Rotation
- /// by X-axis, Rotation by Y-axis and same scaling for all axes. All
- /// other elements, which belongs to this chart area cube (Data points,
- /// grid lines etc.) has to follow same order. Translation and rotation
- /// form composite matrix mainMatrix. Scale has to be allied separately.
- /// </summary>
- /// <param name="innerPlotRectangle">Inner Plotting Area position. Chart area cube has to be inside this rectangle</param>
- /// <param name="depth">Depth of chart area cube</param>
- /// <param name="angleX">Angle of rotation by X axis.</param>
- /// <param name="angleY">Angle of rotation by Y axis.</param>
- /// <param name="perspective">Perspective in percentages</param>
- /// <param name="rightAngleAxis">Right angle flag.</param>
- internal void Initialize(
- RectangleF innerPlotRectangle,
- float depth,
- float angleX,
- float angleY,
- float perspective,
- bool rightAngleAxis )
- {
- // Initialization for mainMatrix
- Reset();
- // Remember non-composite translation
- _translateX = innerPlotRectangle.X+innerPlotRectangle.Width/2;
- _translateY = innerPlotRectangle.Y+innerPlotRectangle.Height/2;
- _translateZ = depth / 2F;
- float width = innerPlotRectangle.Width;
- float height = innerPlotRectangle.Height;
- this._perspective = perspective;
- this._rightAngleAxis = rightAngleAxis;
- // Remember Angles
- this._angleX = angleX;
- this._angleY = angleY;
- // Change Degrees to radians.
- angleX = angleX / 180F * (float)Math.PI;
- angleY = angleY / 180F * (float)Math.PI;
- // Set points for 3D Bar which represents 3D Chart Area Cube.
- Point3D [] points = Set3DBarPoints( width, height, depth );
- // Translate Chart Area Cube WITH CENTER OF ROTATION - COMPOSITE TRANSLATION.
- Translate( _translateX, _translateY, 0 );
- // Non Isometric projection
- if( !rightAngleAxis )
- {
- // Rotate Chart Area Cube by X axis.
- Rotate( angleX, RotationAxis.X );
- // Rotate Chart Area Cube by Y axis.
- Rotate( angleY, RotationAxis.Y );
- }
- else
- {
- if( this._angleY >= 45 )
- {
- // Rotate Chart Area Cube by Y axis.
- Rotate( Math.PI / 2, RotationAxis.Y );
- }
- else if( this._angleY <= -45 )
- {
- // Rotate Chart Area Cube by Y axis.
- Rotate( -Math.PI / 2, RotationAxis.Y );
- }
- }
- // Apply composed transformation ( Translation and rotation ).
- GetValues( points );
- float maxZ = float.MinValue;
- if( perspective != 0F || rightAngleAxis )
- {
- // Find projection plane
- foreach( Point3D point in points )
- {
- if( point.Z > maxZ )
- maxZ = point.Z;
- }
- // Set Projection plane
- _perspectiveZ = maxZ;
- }
- if( perspective != 0F )
- {
- _perspectiveFactor = perspective / 2000F;
- // Apply perspective
- ApplyPerspective( points );
- }
- // Isometric projection is active
- if( rightAngleAxis )
- {
- RightAngleProjection( points );
- float minX = 0F;
- float minY = 0F;
- float maxX = 0F;
- float maxY = 0F;
- // Point loop
- foreach( Point3D point in points )
- {
- if( point.X - _translateX < 0F && Math.Abs( point.X - _translateX ) > minX )
- minX = Math.Abs( point.X - _translateX );
- if( point.X - _translateX >=0F && Math.Abs( point.X - _translateX ) > maxX )
- maxX = Math.Abs( point.X - _translateX );
- if( point.Y - _translateY < 0F && Math.Abs( point.Y - _translateY ) > minY )
- minY = Math.Abs( point.Y - _translateY );
- if( point.Y - _translateY >=0F && Math.Abs( point.Y - _translateY ) > maxY )
- maxY = Math.Abs( point.Y - _translateY );
- }
- _shiftX = (maxX - minX)/2F;
- _shiftY = (maxY - minY)/2F;
- RightAngleShift( points );
- }
- // This code searches for value, which will be used for scaling.
- float maxXScale = float.MinValue;
- float maxYScale = float.MinValue;
- foreach( Point3D point in points )
- {
- // Find maximum relative distance for X axis.
- // Relative distance is (distance from the center of plotting area
- // position) / (distance from the edge of rectangle to
- // the center of the rectangle).
- if( maxXScale < Math.Abs(point.X - _translateX) / width * 2 )
- maxXScale = Math.Abs(point.X - _translateX) / width * 2;
- // Find maximum relative distance for Y axis.
- if( maxYScale < Math.Abs(point.Y - _translateY) / height * 2 )
- maxYScale = Math.Abs(point.Y - _translateY) / height * 2;
- }
- // Remember scale factor
- _scale = (maxYScale > maxXScale ) ? maxYScale : maxXScale;
- // Apply scaling
- Scale( points );
- }
- /// <summary>
- /// Apply transformations on array od 3D Points. Order of operation is
- /// following: Translation ( Set coordinate system for 0:100 to -50:50
- /// Center of rotation is always 0), Composite Translation for X and Y
- /// axes ( Moving center of rotation ), Rotation by X-axis, Rotation
- /// by Y-axis, perspective and same scaling for all axes.
- /// </summary>
- /// <param name="points">3D Points array.</param>
- public void TransformPoints( Point3D[] points )
- {
- TransformPoints( points, true );
- }
- #if RS_DEADCODE
- /// <summary>
- /// This Method returns scale factor
- /// </summary>
- /// <returns></returns>
- internal float GetScale()
- {
- return scale;
- }
- #endif //RS_DEADCODE
- #endregion // Internal and Public Methods
- #region Private Methods
- /// <summary>
- /// Apply transformations on array od 3D Points. Order of operation is
- /// following: Translation ( Set coordinate system for 0:100 to -50:50
- /// Center of rotation is always 0), Composite Translation for X and Y
- /// axes ( Moving center of rotation ), Rotation by X-axis, Rotation
- /// by Y-axis, perspective and same scaling for all axes.
- /// </summary>
- /// <param name="points">3D Points array.</param>
- /// <param name="withPerspective">Applay Perspective</param>
- private void TransformPoints( Point3D[] points, bool withPerspective )
- {
- // Matrix is not initialized.
- if( _mainMatrix == null )
- {
- throw new InvalidOperationException(SR.ExceptionMatrix3DNotinitialized);
- }
- // Translate point. CENTER OF ROTATION is 0 and that center is in
- // the middle of chart area 3D CUBE. Translate method cannot
- // be used because composite translation WILL MOVE
- // CENTER OF ROTATION.
- foreach( Point3D point in points )
- {
- point.X -= _translateX;
- point.Y -= _translateY;
- point.Z -= _translateZ;
- }
- // Transform points using composite mainMatrix. (Translation of points together with
- // Center of rotation and rotations by X and Y axes).
- GetValues( points );
- // Apply perspective
- if( _perspective != 0F && withPerspective )
- {
- ApplyPerspective( points );
- }
- // RightAngle Projection
- if( _rightAngleAxis )
- {
- RightAngleProjection( points );
- RightAngleShift( points );
- }
- // Scales data points. Scaling has to be performed SEPARATELY from
- // composite matrix. If scale is used with composite matrix after
- // rotation, scaling will deform object.
- Scale( points );
- }
- /// <summary>
- /// This method adjusts a position of 3D Chart Area cube. This
- /// method will translate chart for better use of the inner
- /// plotting area. Center of rotation is shifted for
- /// right Angle projection.
- /// </summary>
- /// <param name="points">3D Points array.</param>
- private void RightAngleShift( Point3D [] points )
- {
- foreach( Point3D point in points )
- {
- point.X = point.X - _shiftX;
- point.Y = point.Y - _shiftY;
- }
- }
- /// <summary>
- /// Method used to calculate right Angle projection.
- /// </summary>
- /// <param name="points">3D points array.</param>
- private void RightAngleProjection( Point3D [] points )
- {
- float coorectionAngle = 45F;
- float xFactor = this._angleX / 45;
- float yFactor;
- if( this._angleY >= 45 )
- {
- yFactor = (this._angleY - 90) / coorectionAngle;
- }
- else if ( this._angleY <= -45 )
- {
- yFactor = ( this._angleY + 90 ) / coorectionAngle;
- }
- else
- {
- yFactor = this._angleY / coorectionAngle;
- }
- // Projection formula
- // perspectiveZ - Position of perspective plain.
- // Perspective Factor - Intensity of projection.
- foreach( Point3D point in points )
- {
- point.X = point.X + ( _perspectiveZ - point.Z ) * yFactor;
- point.Y = point.Y - ( _perspectiveZ - point.Z ) * xFactor;
- }
- }
- /// <summary>
- /// Method is used for Planar Geometric projection.
- /// </summary>
- /// <param name="points">3D Points array.</param>
- private void ApplyPerspective( Point3D [] points )
- {
- // Projection formula
- // perspectiveZ - Position of perspective plain.
- // perspectiveFactor - Intensity of projection.
- foreach( Point3D point in points )
- {
- point.X = _translateX + (point.X - _translateX) / ( 1 + (_perspectiveZ - point.Z) * _perspectiveFactor);
- point.Y = _translateY + (point.Y - _translateY) / ( 1 + (_perspectiveZ - point.Z) * _perspectiveFactor);
- }
- }
- /// <summary>
- /// Scales data points. Scaling has to be performed SEPARATELY from
- /// composite matrix. If scale is used with composite matrix after
- /// rotation, scaling will deform object.
- /// </summary>
- /// <param name="points">3D Points array.</param>
- private void Scale( Point3D [] points )
- {
- foreach( Point3D point in points )
- {
- point.X = _translateX + (point.X - _translateX) / _scale;
- point.Y = _translateY + (point.Y - _translateY) / _scale;
- }
- }
- /// <summary>
- /// Prepend to this Matrix object a translation. This method is used
- /// only if CENTER OF ROTATION HAS TO BE MOVED.
- /// </summary>
- /// <param name="dx">Translate in x axis direction.</param>
- /// <param name="dy">Translate in y axis direction.</param>
- /// <param name="dz">Translate in z axis direction.</param>
- private void Translate( float dx, float dy, float dz )
- {
- float [][] translationMatrix = new float[4][];
- translationMatrix[0] = new float[4];
- translationMatrix[1] = new float[4];
- translationMatrix[2] = new float[4];
- translationMatrix[3] = new float[4];
- // Matrix initialization
- // Row loop
- for( int row = 0; row < 4; row ++ )
- {
- // Column loop
- for( int column = 0; column < 4; column ++ )
- {
- // For initialization: Diagonal matrix elements are equal to one
- // and all other elements are equal to zero.
- if( row == column )
- {
- translationMatrix[row][column] = 1F;
- }
- else
- {
- translationMatrix[row][column] = 0F;
- }
- }
- }
- // Set translation values to the matrix
- translationMatrix[0][3] = dx;
- translationMatrix[1][3] = dy;
- translationMatrix[2][3] = dz;
- // Translate main Matrix
- Multiply( translationMatrix, MatrixOrder.Prepend, true );
- }
- /// <summary>
- /// This method initialize and set default values for mainMatrix ( there is no rotation and translation )
- /// </summary>
- private void Reset()
- {
- // First element is row and second element is column !!!
- _mainMatrix = new float[4][];
- _mainMatrix[0] = new float[4];
- _mainMatrix[1] = new float[4];
- _mainMatrix[2] = new float[4];
- _mainMatrix[3] = new float[4];
- // Matrix initialization
- // Row loop
- for( int row = 0; row < 4; row ++ )
- {
- // Column loop
- for( int column = 0; column < 4; column ++ )
- {
- // For initialization: Diagonal matrix elements are equal to one
- // and all other elements are equal to zero.
- if( row == column )
- {
- _mainMatrix[row][column] = 1F;
- }
- else
- {
- _mainMatrix[row][column] = 0F;
- }
- }
- }
- }
- /// <summary>
- /// Multiplies this Matrix object by the matrix specified in the
- /// matrix parameter, and in the order specified in the order parameter.
- /// </summary>
- /// <param name="mulMatrix">The Matrix object by which this Matrix object is to be multiplied.</param>
- /// <param name="order">The MatrixOrder enumeration that represents the order of the multiplication. If the specified order is MatrixOrder.Prepend, this Matrix object is multiplied by the specified matrix in a prepended order. If the specified order is MatrixOrder.Append, this Matrix object is multiplied by the specified matrix in an appended order.</param>
- /// <param name="setMainMatrix">Set main matrix to be result of multiplication</param>
- /// <returns>Matrix multiplication result.</returns>
- private float[][] Multiply( float [][] mulMatrix, MatrixOrder order, bool setMainMatrix )
- {
- // A matrix which is result of matrix multiplication
- // of mulMatrix and mainMatrix
- float [][] resultMatrix = new float[4][];
- resultMatrix[0] = new float[4];
- resultMatrix[1] = new float[4];
- resultMatrix[2] = new float[4];
- resultMatrix[3] = new float[4];
- // Row loop
- for( int row = 0; row < 4; row ++ )
- {
- // Column loop
- for( int column = 0; column < 4; column ++ )
- {
- // Initialize element
- resultMatrix[row][column ] = 0F;
- for( int sumIndx = 0; sumIndx < 4; sumIndx ++ )
- {
- // Find matrix element
- if( order == MatrixOrder.Prepend )
- {
- // Order of matrix multiplication
- resultMatrix[row][column ] += _mainMatrix[row][sumIndx ] * mulMatrix[sumIndx][column];
- }
- else
- {
- // Order of matrix multiplication
- resultMatrix[row][column] += mulMatrix[row][sumIndx] * _mainMatrix[sumIndx][column];
- }
- }
- }
- }
- // Set result matrix to be main matrix
- if( setMainMatrix )
- {
- _mainMatrix = resultMatrix;
- }
- return resultMatrix;
- }
- /// <summary>
- /// Multiplies this Matrix object by the Vector specified in the
- /// vector parameter.
- /// </summary>
- /// <param name="mulVector">The vector object by which this Matrix object is to be multiplied.</param>
- /// <param name="resultVector">Vector which is result of matrix and vector multiplication.</param>
- private void MultiplyVector( float [] mulVector, ref float [] resultVector )
- {
- // Row loop
- for( int row = 0; row < 3; row ++ )
- {
- // Initialize element
- resultVector[ row ] = 0F;
- // Column loop
- for( int column = 0; column < 4; column ++ )
- {
- // Find matrix element
- resultVector[ row ] += _mainMatrix[row][column] * mulVector[ column ];
- }
- }
- }
- /// <summary>
- /// Prepend to this Matrix object a clockwise rotation, around the axis and by the specified angle.
- /// </summary>
- /// <param name="angle">Angle to rotate</param>
- /// <param name="axis">Axis used for rotation</param>
- private void Rotate( double angle, RotationAxis axis )
- {
- float [][] rotationMatrix = new float[4][];
- rotationMatrix[0] = new float[4];
- rotationMatrix[1] = new float[4];
- rotationMatrix[2] = new float[4];
- rotationMatrix[3] = new float[4];
- // Change angle direction
- angle = -1F * angle;
- // Matrix initialization
- // Row loop
- for( int row = 0; row < 4; row ++ )
- {
- // Column loop
- for( int column = 0; column < 4; column ++ )
- {
- // For initialization: Diagonal matrix elements are equal to one
- // and all other elements are equal to zero.
- if( row == column )
- {
- rotationMatrix[row][column] = 1F;
- }
- else
- {
- rotationMatrix[row][column] = 0F;
- }
- }
- }
- // Rotation about axis
- switch( axis )
- {
- // Rotation about X axis
- case RotationAxis.X:
- rotationMatrix[1][1] = (float)Math.Cos( angle );
- rotationMatrix[1][2] = (float)-Math.Sin( angle );
- rotationMatrix[2][1] = (float)Math.Sin( angle );
- rotationMatrix[2][2] = (float)Math.Cos( angle );
- break;
- // Rotation about Y axis
- case RotationAxis.Y:
- rotationMatrix[0][0] = (float)Math.Cos( angle );
- rotationMatrix[0][2] = (float)Math.Sin( angle );
- rotationMatrix[2][0] = (float)-Math.Sin( angle );
- rotationMatrix[2][2] = (float)Math.Cos( angle );
- break;
- // Rotation about Z axis
- case RotationAxis.Z:
- rotationMatrix[0][0] = (float)Math.Cos( angle );
- rotationMatrix[0][1] = (float)-Math.Sin( angle );
- rotationMatrix[1][0] = (float)Math.Sin( angle );
- rotationMatrix[1][1] = (float)Math.Cos( angle );
- break;
- }
- // Rotate Main matrix
- Multiply( rotationMatrix, MatrixOrder.Prepend, true );
- }
- /// <summary>
- /// Returns transformed x and y values from x, y and z values
- /// and composed main matrix values (All rotations,
- /// translations and scaling).
- /// </summary>
- /// <param name="points">Array of 3D points.</param>
- private void GetValues( Point3D [] points )
- {
- // Create one dimensional matrix (vector)
- float [] inputVector = new float[4];
- // A vector which is result of matrix and vector multiplication
- float [] resultVector = new float[4];
- foreach( Point3D point in points )
- {
- // Fill input vector with x, y and z coordinates
- inputVector[0] = point.X;
- inputVector[1] = point.Y;
- inputVector[2] = point.Z;
- inputVector[3] = 1;
- // Apply 3D transformations.
- MultiplyVector( inputVector, ref resultVector );
- // Return x and y coordinates.
- point.X = resultVector[0];
- point.Y = resultVector[1];
- point.Z = resultVector[2];
- }
- }
- /// <summary>
- /// Set points for 3D Bar which represents 3D Chart Area.
- /// </summary>
- /// <param name="dx">Width of the bar 3D.</param>
- /// <param name="dy">Height of the bar 3D.</param>
- /// <param name="dz">Depth of the bar 3D.</param>
- /// <returns>Collection of Points 3D.</returns>
- private Point3D [] Set3DBarPoints( float dx, float dy, float dz )
- {
- Point3D [] points = new Point3D[8];
- // ********************************************
- // 3D Bar side: Front
- // ********************************************
- points[0] = new Point3D(-dx/2, -dy/2, dz/2);
- points[1] = new Point3D(dx/2, -dy/2, dz/2);
- points[2] = new Point3D(dx/2, dy/2, dz/2);
- points[3] = new Point3D(-dx/2, dy/2, dz/2);
- // ********************************************
- // 3D Bar side: Back
- // ********************************************
- points[4] = new Point3D(-dx/2, -dy/2, -dz/2);
- points[5] = new Point3D(dx/2, -dy/2, -dz/2);
- points[6] = new Point3D(dx/2, dy/2, -dz/2);
- points[7] = new Point3D(-dx/2, dy/2, -dz/2);
- return points;
- }
- #endregion // Private Methods
- #region Lighting Methods
- /// <summary>
- /// Initial Lighting. Use matrix transformation only once
- /// for Normal vectors.
- /// </summary>
- /// <param name="lightStyle">LightStyle Style</param>
- internal void InitLight( LightStyle lightStyle )
- {
- // Set LightStyle Style
- this._lightStyle = lightStyle;
- // Center of rotation
- _lightVectors[0] = new Point3D( 0F, 0F, 0F );
- // Front side normal Vector.
- _lightVectors[1] = new Point3D( 0F, 0F, 1F );
- // Back side normal Vector.
- _lightVectors[2] = new Point3D( 0F, 0F, -1F );
- // Left side normal Vector.
- _lightVectors[3] = new Point3D( -1F, 0F, 0F );
- // Right side normal Vector.
- _lightVectors[4] = new Point3D( 1F, 0F, 0F );
- // Top side normal Vector.
- _lightVectors[5] = new Point3D( 0F, -1F, 0F );
- // Bottom side normal Vector.
- _lightVectors[6] = new Point3D( 0F, 1F, 0F );
- // Apply matrix transformations
- TransformPoints( _lightVectors, false );
- // ********************************************************
- // LightStyle Vector and normal vectors have to have same center.
- // Shift Normal vectors.
- // ********************************************************
- // Front Side shift
- _lightVectors[1].X -= _lightVectors[0].X;
- _lightVectors[1].Y -= _lightVectors[0].Y;
- _lightVectors[1].Z -= _lightVectors[0].Z;
- // Back Side shift
- _lightVectors[2].X -= _lightVectors[0].X;
- _lightVectors[2].Y -= _lightVectors[0].Y;
- _lightVectors[2].Z -= _lightVectors[0].Z;
- // Left Side shift
- _lightVectors[3].X -= _lightVectors[0].X;
- _lightVectors[3].Y -= _lightVectors[0].Y;
- _lightVectors[3].Z -= _lightVectors[0].Z;
- // Right Side shift
- _lightVectors[4].X -= _lightVectors[0].X;
- _lightVectors[4].Y -= _lightVectors[0].Y;
- _lightVectors[4].Z -= _lightVectors[0].Z;
- // Top Side shift
- _lightVectors[5].X -= _lightVectors[0].X;
- _lightVectors[5].Y -= _lightVectors[0].Y;
- _lightVectors[5].Z -= _lightVectors[0].Z;
- // Bottom Side shift
- _lightVectors[6].X -= _lightVectors[0].X;
- _lightVectors[6].Y -= _lightVectors[0].Y;
- _lightVectors[6].Z -= _lightVectors[0].Z;
- }
- /// <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>
- /// 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>
- /// 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>
- /// Returns the angle between two 3D vectors (a and b);
- /// </summary>
- /// <param name="a">First vector</param>
- /// <param name="b">Second Vector</param>
- /// <returns>Angle between vectors</returns>
- private float GetAngle(Point3D a,Point3D b)
- {
- double angle;
- angle = Math.Acos( ( a.X * b.X + a.Y * b.Y + a.Z * b.Z ) / ( Math.Sqrt( a.X * a.X + a.Y * a.Y + a.Z * a.Z ) * Math.Sqrt( b.X * b.X + b.Y * b.Y + b.Z * b.Z ) ) );
- return (float)angle;
- }
- #endregion
- }
- }
- [Document Outline] [Project Explorer] [Namespace Explorer]
Add Comment
Please, Sign In to add comment