here2share

# Matrix3D.cs

Feb 12th, 2020
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 39.30 KB | None | 0 0
  1. //-------------------------------------------------------------
  2. // <copyright company=’Microsoft Corporation’>
  3. //   Copyright © Microsoft Corporation. All Rights Reserved.
  4. // </copyright>
  5. //-------------------------------------------------------------
  6. // @owner=alexgor, deliant
  7. //=================================================================
  8. //  File:       Matrix3D.cs
  9. //
  10. //  Namespace:  DataVisualization.Charting
  11. //
  12. //  Classes:    Matrix3D
  13. //
  14. //  Purpose:    Matrix3D class is used during the 3D drawings to
  15. //              transform plotting area 3D coordinates into the 2D
  16. //              projection coordinates based on rotation and
  17. //              perspective settings.
  18. //
  19. //  Reviewed:   AG - Dec 4, 2002
  20. //              AG - Microsoft 14, 2007
  21. //
  22. //===================================================================
  23.  
  24. #region Used namespaces
  25.  
  26. using System;
  27. using System.Drawing;
  28. using System.Drawing.Drawing2D;
  29. using System.Drawing.Text;
  30. using System.Drawing.Imaging;
  31. using System.ComponentModel;
  32. using System.Collections;
  33.  
  34. #if Microsoft_CONTROL
  35.     using System.Windows.Forms.DataVisualization.Charting;
  36.     using System.Windows.Forms.DataVisualization.Charting.Data;
  37.     using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
  38.     using System.Windows.Forms.DataVisualization.Charting.Utilities;
  39.     using System.Windows.Forms.DataVisualization.Charting.Borders3D;
  40.  
  41. #else
  42.     //using System.Web.UI.DataVisualization.Charting.Utilities;
  43.     //using System.Web.UI.DataVisualization.Charting.Borders3D;
  44. #endif
  45.  
  46. #endregion
  47.  
  48. #if Microsoft_CONTROL
  49.     namespace System.Windows.Forms.DataVisualization.Charting
  50. #else
  51. namespace System.Web.UI.DataVisualization.Charting
  52.  
  53. #endif
  54. {
  55.     /// <summary>
  56.     /// This class is responsible for all 3D coordinates transformations: Translation,
  57.     /// Rotation, Scale, Perspective and RightAngle Projection. Translation
  58.     /// and rotation are stored in composite matrix (mainMatrix), and scaling,
  59.     /// projection and non-composite translation are stored in private fields.
  60.     /// Matrix is initialized with Chart Area 3D cube, which is invisible boundary
  61.     /// cube of 3D Chart area. The matrix has to be initialized every time
  62.     /// when angles, position or perspective parameters are changed. Method
  63.     /// TransformPoints will apply 3D Transformation on points using
  64.     /// Initialization values: Main matrix and other initialization values.
  65.     /// </summary>
  66.     internal class Matrix3D
  67.     {
  68.         #region Enumerations
  69.  
  70.         /// <summary>
  71.         /// 3D Axis used for rotation
  72.         /// </summary>
  73.         private enum RotationAxis
  74.         {
  75.             /// <summary>
  76.             /// Rotation around X axis.
  77.             /// </summary>
  78.             X,
  79.  
  80.             /// <summary>
  81.             /// Rotation around Y axis.
  82.             /// </summary>
  83.             Y,
  84.  
  85.             /// <summary>
  86.             /// Rotation around Z axis.
  87.             /// </summary>
  88.             Z
  89.         }
  90.  
  91.         #endregion // Enumerations
  92.  
  93.         #region Fields
  94.  
  95.         /// <summary>
  96.         /// Composite matrix.
  97.         /// </summary>
  98.         private float [][] _mainMatrix;
  99.        
  100.         /// <summary>
  101.         /// Default translation for chart area cube ( without composition ).
  102.         /// </summary>
  103.         private float _translateX;
  104.  
  105.         /// <summary>
  106.         /// Default translation for chart area cube ( without composition ).
  107.         /// </summary>
  108.         private float _translateY;
  109.  
  110.         /// <summary>
  111.         /// Default translation for chart area cube ( without composition ).
  112.         /// </summary>
  113.         private float _translateZ;
  114.  
  115.         /// <summary>
  116.         /// The value, which is used to rescale chart area.
  117.         /// </summary>
  118.         private float _scale;
  119.  
  120.         /// <summary>
  121.         /// The value used for Isometric Shift.
  122.         /// </summary>
  123.         private float _shiftX;
  124.  
  125.         /// <summary>
  126.         /// The value used for Isometric Shift.
  127.         /// </summary>
  128.         private float _shiftY;
  129.  
  130.         /// <summary>
  131.         /// Perspective value.
  132.         /// </summary>
  133.         internal float _perspective;
  134.  
  135.         /// <summary>
  136.         /// Isometric projection.
  137.         /// </summary>
  138.         private bool _rightAngleAxis;
  139.  
  140.         /// <summary>
  141.         /// The value, which is used for perspective.
  142.         /// </summary>
  143.         private float _perspectiveFactor = float.NaN;
  144.  
  145.         /// <summary>
  146.         /// The value, which is used to set projection plane.
  147.         /// </summary>
  148.         private float _perspectiveZ;
  149.  
  150.         /// <summary>
  151.         /// X Angle.
  152.         /// </summary>
  153.         private float _angleX;
  154.  
  155.         /// <summary>
  156.         /// Y Angle.
  157.         /// </summary>
  158.         private float _angleY;
  159.  
  160.         /// <summary>
  161.         /// Private fields used for lighting
  162.         /// </summary>
  163.         Point3D [] _lightVectors = new Point3D[7];
  164.  
  165.         /// <summary>
  166.         /// LightStyle Style
  167.         /// </summary>
  168.         LightStyle _lightStyle;
  169.  
  170.         #endregion // Fields
  171.  
  172.         #region Properties
  173.  
  174.         /// <summary>
  175.         /// Gets the X Angle.
  176.         /// </summary>
  177.         internal float AngleX
  178.         {
  179.             get { return _angleX; }
  180.         }
  181.  
  182.         /// <summary>
  183.         /// Gets the Y Angle.
  184.         /// </summary>
  185.         internal float AngleY
  186.         {
  187.             get { return _angleY; }
  188.         }
  189.  
  190.         /// <summary>
  191.         /// Get perspective value.
  192.         /// </summary>
  193.         internal float Perspective
  194.         {
  195.             get { return _perspective; }
  196.         }
  197.  
  198.         #endregion // Properties
  199.  
  200.         #region Internal and Public Methods
  201.  
  202.         /// <summary>
  203.         /// Constructor for Matrix 3D
  204.         /// </summary>
  205.         public Matrix3D()
  206.         {
  207.         }
  208.  
  209.         /// <summary>
  210.         /// Checks if 3D matrix was initialized.
  211.         /// </summary>
  212.         /// <returns>True if matrix was initialized.</returns>
  213.         public bool IsInitialized()
  214.         {
  215.             return (this._mainMatrix != null);
  216.         }
  217.  
  218.         /// <summary>
  219.         /// Initialize Matrix 3D. This method calculates how much a chart area
  220.         /// cube has to be resized to fit Inner Plotting Area rectangle. Order
  221.         /// of operation is following: Translation for X and Y axes, Rotation
  222.         /// by X-axis, Rotation by Y-axis and same scaling for all axes. All
  223.         /// other elements, which belongs to this chart area cube (Data points,
  224.         /// grid lines etc.) has to follow same order. Translation and rotation
  225.         /// form composite matrix mainMatrix. Scale has to be allied separately.
  226.         /// </summary>
  227.         /// <param name="innerPlotRectangle">Inner Plotting Area position. Chart area cube has to be inside this rectangle</param>
  228.         /// <param name="depth">Depth of chart area cube</param>
  229.         /// <param name="angleX">Angle of rotation by X axis.</param>
  230.         /// <param name="angleY">Angle of rotation by Y axis.</param>
  231.         /// <param name="perspective">Perspective in percentages</param>
  232.         /// <param name="rightAngleAxis">Right angle flag.</param>
  233.         internal void Initialize(
  234.             RectangleF innerPlotRectangle,
  235.             float depth,
  236.             float angleX,
  237.             float angleY,
  238.             float perspective,
  239.             bool rightAngleAxis )
  240.         {
  241.             // Initialization for mainMatrix
  242.             Reset();
  243.  
  244.             // Remember non-composite translation
  245.             _translateX = innerPlotRectangle.X+innerPlotRectangle.Width/2;
  246.             _translateY = innerPlotRectangle.Y+innerPlotRectangle.Height/2;
  247.             _translateZ = depth / 2F;
  248.             float width = innerPlotRectangle.Width;
  249.             float height = innerPlotRectangle.Height;
  250.             this._perspective = perspective;
  251.             this._rightAngleAxis = rightAngleAxis;
  252.  
  253.             // Remember Angles
  254.             this._angleX = angleX;
  255.             this._angleY = angleY;
  256.            
  257.             // Change Degrees to radians.
  258.             angleX = angleX / 180F * (float)Math.PI;
  259.             angleY = angleY / 180F * (float)Math.PI;
  260.  
  261.             // Set points for 3D Bar which represents 3D Chart Area Cube.
  262.             Point3D [] points = Set3DBarPoints( width, height, depth );
  263.            
  264.             // Translate Chart Area Cube WITH CENTER OF ROTATION - COMPOSITE TRANSLATION.
  265.             Translate( _translateX, _translateY, 0 );
  266.  
  267.             // Non Isometric projection
  268.             if( !rightAngleAxis )
  269.             {
  270.                 // Rotate Chart Area Cube by X axis.
  271.                 Rotate( angleX, RotationAxis.X );
  272.  
  273.                 // Rotate Chart Area Cube by Y axis.
  274.                 Rotate( angleY, RotationAxis.Y );
  275.             }
  276.             else
  277.             {
  278.                 if( this._angleY >= 45 )
  279.                 {
  280.                     // Rotate Chart Area Cube by Y axis.
  281.                     Rotate( Math.PI / 2, RotationAxis.Y );
  282.                 }
  283.                 else if( this._angleY <= -45 )
  284.                 {
  285.                     // Rotate Chart Area Cube by Y axis.
  286.                     Rotate( -Math.PI / 2, RotationAxis.Y );
  287.                 }
  288.             }
  289.            
  290.             // Apply composed transformation ( Translation and rotation ).
  291.             GetValues( points );
  292.  
  293.             float maxZ = float.MinValue;
  294.  
  295.             if( perspective != 0F || rightAngleAxis )
  296.             {
  297.                 // Find projection plane
  298.                 foreach( Point3D point in points )
  299.                 {
  300.                     if( point.Z > maxZ )
  301.                         maxZ = point.Z;
  302.                 }
  303.  
  304.                 // Set Projection plane
  305.                 _perspectiveZ = maxZ;
  306.             }
  307.  
  308.             if( perspective != 0F )
  309.             {
  310.                 _perspectiveFactor = perspective / 2000F;
  311.  
  312.                 // Apply perspective
  313.                 ApplyPerspective( points );
  314.             }
  315.                
  316.             // Isometric projection is active
  317.             if( rightAngleAxis )
  318.             {
  319.                 RightAngleProjection( points );
  320.  
  321.                 float minX = 0F;
  322.                 float minY = 0F;
  323.                 float maxX = 0F;
  324.                 float maxY = 0F;
  325.  
  326.                 // Point loop
  327.                 foreach( Point3D point in points )
  328.                 {
  329.                     if( point.X - _translateX < 0F  && Math.Abs( point.X - _translateX ) > minX )
  330.                         minX = Math.Abs( point.X - _translateX );
  331.                    
  332.                     if( point.X - _translateX >=0F  && Math.Abs( point.X - _translateX ) > maxX )
  333.                         maxX = Math.Abs( point.X - _translateX );
  334.  
  335.                     if( point.Y - _translateY < 0F  && Math.Abs( point.Y - _translateY ) > minY )
  336.                         minY = Math.Abs( point.Y - _translateY );
  337.                    
  338.                     if( point.Y - _translateY >=0F  && Math.Abs( point.Y - _translateY ) > maxY )
  339.                         maxY = Math.Abs( point.Y - _translateY );
  340.                 }
  341.  
  342.                 _shiftX = (maxX - minX)/2F;
  343.                 _shiftY = (maxY - minY)/2F;
  344.                 RightAngleShift( points );
  345.             }
  346.                                
  347.             // This code searches for value, which will be used for scaling.
  348.             float maxXScale = float.MinValue;
  349.             float maxYScale = float.MinValue;
  350.  
  351.             foreach( Point3D point in points )
  352.             {
  353.                 // Find maximum relative distance for X axis.
  354.                 // Relative distance is (distance from the center of plotting area
  355.                 // position) / (distance from the edge of rectangle to
  356.                 // the center of the rectangle).
  357.                 if( maxXScale < Math.Abs(point.X - _translateX) / width * 2 )
  358.                     maxXScale = Math.Abs(point.X - _translateX) / width * 2;
  359.                
  360.                 // Find maximum relative distance for Y axis.
  361.                 if( maxYScale < Math.Abs(point.Y - _translateY) / height * 2 )
  362.                     maxYScale = Math.Abs(point.Y - _translateY) / height * 2;
  363.             }
  364.  
  365.             // Remember scale factor
  366.             _scale = (maxYScale > maxXScale ) ? maxYScale : maxXScale;
  367.  
  368.             // Apply scaling
  369.             Scale( points );
  370.            
  371.         }
  372.  
  373.         /// <summary>
  374.         /// Apply transformations on array od 3D Points. Order of operation is
  375.         /// following: Translation ( Set coordinate system for 0:100 to -50:50
  376.         /// Center of rotation is always 0), Composite Translation for X and Y
  377.         /// axes ( Moving center of rotation ), Rotation by X-axis, Rotation
  378.         /// by Y-axis, perspective and same scaling for all axes.
  379.         /// </summary>
  380.         /// <param name="points">3D Points array.</param>
  381.         public void TransformPoints( Point3D[] points )
  382.         {
  383.             TransformPoints( points, true );
  384.         }
  385. #if RS_DEADCODE
  386.         /// <summary>
  387.         /// This Method returns scale factor
  388.         /// </summary>
  389.         /// <returns></returns>
  390.         internal float GetScale()
  391.         {
  392.             return scale;
  393.         }
  394. #endif //RS_DEADCODE
  395.         #endregion // Internal and Public Methods
  396.  
  397.         #region Private Methods
  398.  
  399.         /// <summary>
  400.         /// Apply transformations on array od 3D Points. Order of operation is
  401.         /// following: Translation ( Set coordinate system for 0:100 to -50:50
  402.         /// Center of rotation is always 0), Composite Translation for X and Y
  403.         /// axes ( Moving center of rotation ), Rotation by X-axis, Rotation
  404.         /// by Y-axis, perspective and same scaling for all axes.
  405.         /// </summary>
  406.         /// <param name="points">3D Points array.</param>
  407.         /// <param name="withPerspective">Applay Perspective</param>
  408.         private void TransformPoints( Point3D[] points, bool withPerspective )
  409.         {
  410.             // Matrix is not initialized.
  411.             if( _mainMatrix == null )
  412.             {
  413.                 throw new InvalidOperationException(SR.ExceptionMatrix3DNotinitialized);
  414.             }
  415.  
  416.             // Translate point. CENTER OF ROTATION is 0 and that center is in
  417.             // the middle of chart area 3D CUBE. Translate method cannot
  418.             // be used because composite translation WILL MOVE
  419.             // CENTER OF ROTATION.
  420.             foreach( Point3D point in points )
  421.             {
  422.                 point.X -= _translateX;
  423.                 point.Y -= _translateY;
  424.                 point.Z -= _translateZ;
  425.             }
  426.        
  427.             // Transform points using composite mainMatrix. (Translation of points together with
  428.             // Center of rotation and rotations by X and Y axes).
  429.             GetValues( points );
  430.  
  431.             // Apply perspective
  432.             if( _perspective != 0F && withPerspective )
  433.             {
  434.                 ApplyPerspective( points );
  435.             }
  436.            
  437.             // RightAngle Projection
  438.             if( _rightAngleAxis )
  439.             {
  440.                 RightAngleProjection( points );
  441.                 RightAngleShift( points );
  442.             }
  443.  
  444.             // Scales data points. Scaling has to be performed SEPARATELY from
  445.             // composite matrix. If scale is used with composite matrix after
  446.             // rotation, scaling will deform object.
  447.             Scale( points );
  448.         }
  449.        
  450.         /// <summary>
  451.         /// This method adjusts a position of 3D Chart Area cube. This
  452.         /// method will translate chart for better use of the inner
  453.         /// plotting area. Center of rotation is shifted for
  454.         /// right Angle projection.
  455.         /// </summary>
  456.         /// <param name="points">3D Points array.</param>
  457.         private void RightAngleShift( Point3D [] points )
  458.         {
  459.             foreach( Point3D point in points )
  460.             {
  461.                 point.X = point.X - _shiftX;  
  462.                 point.Y = point.Y - _shiftY;  
  463.             }
  464.         }
  465.  
  466.         /// <summary>
  467.         /// Method used to calculate right Angle projection.
  468.         /// </summary>
  469.         /// <param name="points">3D points array.</param>
  470.         private void RightAngleProjection( Point3D [] points )
  471.         {
  472.             float coorectionAngle = 45F;
  473.        
  474.             float xFactor = this._angleX / 45;
  475.  
  476.             float yFactor;
  477.            
  478.             if( this._angleY >= 45 )
  479.             {
  480.                 yFactor = (this._angleY - 90) / coorectionAngle;
  481.             }
  482.             else if ( this._angleY <= -45 )
  483.             {
  484.                 yFactor = ( this._angleY + 90 ) / coorectionAngle;
  485.             }
  486.             else
  487.             {
  488.                 yFactor = this._angleY / coorectionAngle;
  489.             }
  490.            
  491.             // Projection formula
  492.             // perspectiveZ - Position of perspective plain.
  493.             // Perspective Factor - Intensity of projection.
  494.             foreach( Point3D point in points )
  495.             {
  496.                 point.X = point.X + ( _perspectiveZ - point.Z ) * yFactor;  
  497.                 point.Y = point.Y - ( _perspectiveZ - point.Z ) * xFactor;  
  498.             }
  499.         }
  500.  
  501.         /// <summary>
  502.         /// Method is used for Planar Geometric projection.
  503.         /// </summary>
  504.         /// <param name="points">3D Points array.</param>
  505.         private void ApplyPerspective( Point3D [] points )
  506.         {
  507.             // Projection formula
  508.             // perspectiveZ - Position of perspective plain.
  509.             // perspectiveFactor - Intensity of projection.
  510.             foreach( Point3D point in points )
  511.             {
  512.                 point.X = _translateX + (point.X - _translateX) / ( 1 + (_perspectiveZ - point.Z) * _perspectiveFactor);  
  513.                 point.Y = _translateY + (point.Y - _translateY) / ( 1 + (_perspectiveZ - point.Z) * _perspectiveFactor);
  514.             }
  515.         }
  516.  
  517.         /// <summary>
  518.         /// Scales data points. Scaling has to be performed SEPARATELY from
  519.         /// composite matrix. If scale is used with composite matrix after
  520.         /// rotation, scaling will deform object.
  521.         /// </summary>
  522.         /// <param name="points">3D Points array.</param>
  523.         private void Scale( Point3D [] points )
  524.         {
  525.             foreach( Point3D point in points )
  526.             {
  527.                 point.X = _translateX + (point.X - _translateX) / _scale;
  528.                 point.Y = _translateY + (point.Y - _translateY) / _scale;
  529.             }
  530.         }
  531.  
  532.         /// <summary>
  533.         /// Prepend to this Matrix object a translation. This method is used
  534.         /// only if CENTER OF ROTATION HAS TO BE MOVED.
  535.         /// </summary>
  536.         /// <param name="dx">Translate in x axis direction.</param>
  537.         /// <param name="dy">Translate in y axis direction.</param>
  538.         /// <param name="dz">Translate in z axis direction.</param>
  539.         private void Translate( float dx, float dy, float dz )
  540.         {
  541.             float [][] translationMatrix = new float[4][];
  542.             translationMatrix[0] = new float[4];
  543.             translationMatrix[1] = new float[4];
  544.             translationMatrix[2] = new float[4];
  545.             translationMatrix[3] = new float[4];
  546.  
  547.             // Matrix initialization
  548.             // Row loop
  549.             for( int row = 0; row < 4; row ++ )
  550.             {
  551.                 // Column loop
  552.                 for( int column = 0; column < 4; column ++ )
  553.                 {
  554.                     // For initialization: Diagonal matrix elements are equal to one
  555.                     // and all other elements are equal to zero.
  556.                     if( row == column )
  557.                     {
  558.                         translationMatrix[row][column] = 1F;
  559.                     }
  560.                     else
  561.                     {
  562.                         translationMatrix[row][column] = 0F;
  563.                     }
  564.                 }
  565.             }
  566.        
  567.             // Set translation values to the matrix
  568.             translationMatrix[0][3] = dx;
  569.             translationMatrix[1][3] = dy;
  570.             translationMatrix[2][3] = dz;
  571.        
  572.             // Translate main Matrix
  573.             Multiply( translationMatrix, MatrixOrder.Prepend, true );
  574.        
  575.         }
  576.  
  577.         /// <summary>
  578.         /// This method initialize and set default values for mainMatrix ( there is no rotation and translation )
  579.         /// </summary>
  580.         private void Reset()
  581.         {
  582.             // First element is row and second element is column !!!
  583.             _mainMatrix = new float[4][];
  584.             _mainMatrix[0] = new float[4];
  585.             _mainMatrix[1] = new float[4];
  586.             _mainMatrix[2] = new float[4];
  587.             _mainMatrix[3] = new float[4];
  588.  
  589.             // Matrix initialization
  590.             // Row loop
  591.             for( int row = 0; row < 4; row ++ )
  592.             {
  593.                 // Column loop
  594.                 for( int column = 0; column < 4; column ++ )
  595.                 {
  596.                     // For initialization: Diagonal matrix elements are equal to one
  597.                     // and all other elements are equal to zero.
  598.                     if( row == column )
  599.                     {
  600.                         _mainMatrix[row][column] = 1F;
  601.                     }
  602.                     else
  603.                     {
  604.                         _mainMatrix[row][column] = 0F;
  605.                     }
  606.                 }
  607.             }
  608.         }
  609.  
  610.  
  611.         /// <summary>
  612.         /// Multiplies this Matrix object by the matrix specified in the
  613.         /// matrix parameter, and in the order specified in the order parameter.
  614.         /// </summary>
  615.         /// <param name="mulMatrix">The Matrix object by which this Matrix object is to be multiplied.</param>
  616.         /// <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>
  617.         /// <param name="setMainMatrix">Set main matrix to be result of multiplication</param>
  618.         /// <returns>Matrix multiplication result.</returns>
  619.         private float[][] Multiply( float [][] mulMatrix, MatrixOrder order, bool setMainMatrix )
  620.         {
  621.             // A matrix which is result of matrix multiplication
  622.             // of mulMatrix and mainMatrix
  623.             float [][] resultMatrix = new float[4][];
  624.             resultMatrix[0] = new float[4];
  625.             resultMatrix[1] = new float[4];
  626.             resultMatrix[2] = new float[4];
  627.             resultMatrix[3] = new float[4];
  628.  
  629.             // Row loop
  630.             for( int row = 0; row < 4; row ++ )
  631.             {
  632.                 // Column loop
  633.                 for( int column = 0; column < 4; column ++ )
  634.                 {
  635.                     // Initialize element
  636.                     resultMatrix[row][column ] = 0F;
  637.                     for( int sumIndx = 0; sumIndx < 4; sumIndx ++ )
  638.                     {
  639.                         // Find matrix element
  640.                         if( order == MatrixOrder.Prepend )
  641.                         {
  642.                             // Order of matrix multiplication
  643.                             resultMatrix[row][column ] += _mainMatrix[row][sumIndx ] * mulMatrix[sumIndx][column];
  644.                         }
  645.                         else
  646.                         {
  647.                             // Order of matrix multiplication
  648.                             resultMatrix[row][column] += mulMatrix[row][sumIndx] * _mainMatrix[sumIndx][column];
  649.                         }
  650.                     }
  651.                 }
  652.             }
  653.  
  654.             // Set result matrix to be main matrix
  655.             if( setMainMatrix )
  656.             {
  657.                 _mainMatrix = resultMatrix;
  658.             }
  659.  
  660.             return resultMatrix;
  661.         }
  662.  
  663.  
  664.         /// <summary>
  665.         /// Multiplies this Matrix object by the Vector specified in the
  666.         /// vector parameter.
  667.         /// </summary>
  668.         /// <param name="mulVector">The vector object by which this Matrix object is to be multiplied.</param>
  669.         /// <param name="resultVector">Vector which is result of matrix and vector multiplication.</param>
  670.         private void MultiplyVector( float [] mulVector, ref float [] resultVector )
  671.         {
  672.             // Row loop
  673.             for( int row = 0; row < 3; row ++ )
  674.             {
  675.                 // Initialize element
  676.                 resultVector[ row ] = 0F;
  677.  
  678.                 // Column loop
  679.                 for( int column = 0; column < 4; column ++ )
  680.                 {
  681.                     // Find matrix element
  682.                     resultVector[ row ] += _mainMatrix[row][column] * mulVector[ column ];
  683.                 }
  684.             }
  685.         }
  686.  
  687.         /// <summary>
  688.         /// Prepend to this Matrix object a clockwise rotation, around the axis and by the specified angle.
  689.         /// </summary>
  690.         /// <param name="angle">Angle to rotate</param>
  691.         /// <param name="axis">Axis used for rotation</param>
  692.         private void Rotate( double angle, RotationAxis axis )
  693.         {
  694.             float [][] rotationMatrix = new float[4][];
  695.             rotationMatrix[0] = new float[4];
  696.             rotationMatrix[1] = new float[4];
  697.             rotationMatrix[2] = new float[4];
  698.             rotationMatrix[3] = new float[4];
  699.  
  700.             // Change angle direction
  701.             angle = -1F * angle;
  702.  
  703.             // Matrix initialization
  704.             // Row loop
  705.             for( int row = 0; row < 4; row ++ )
  706.             {
  707.                 // Column loop
  708.                 for( int column = 0; column < 4; column ++ )
  709.                 {
  710.                     // For initialization: Diagonal matrix elements are equal to one
  711.                     // and all other elements are equal to zero.
  712.                     if( row == column )
  713.                     {
  714.                         rotationMatrix[row][column] = 1F;
  715.                     }
  716.                     else
  717.                     {
  718.                         rotationMatrix[row][column] = 0F;
  719.                     }
  720.                 }
  721.             }
  722.  
  723.             // Rotation about axis
  724.             switch( axis )
  725.             {
  726.                     // Rotation about X axis
  727.                 case RotationAxis.X:
  728.                     rotationMatrix[1][1] = (float)Math.Cos( angle );
  729.                     rotationMatrix[1][2] = (float)-Math.Sin( angle );
  730.                     rotationMatrix[2][1] = (float)Math.Sin( angle );
  731.                     rotationMatrix[2][2] = (float)Math.Cos( angle );
  732.                     break;
  733.  
  734.                     // Rotation about Y axis
  735.                 case RotationAxis.Y:
  736.                     rotationMatrix[0][0] = (float)Math.Cos( angle );
  737.                     rotationMatrix[0][2] = (float)Math.Sin( angle );
  738.                     rotationMatrix[2][0] = (float)-Math.Sin( angle );
  739.                     rotationMatrix[2][2] = (float)Math.Cos( angle );
  740.                     break;
  741.  
  742.                     // Rotation about Z axis
  743.                 case RotationAxis.Z:
  744.                     rotationMatrix[0][0] = (float)Math.Cos( angle );
  745.                     rotationMatrix[0][1] = (float)-Math.Sin( angle );
  746.                     rotationMatrix[1][0] = (float)Math.Sin( angle );
  747.                     rotationMatrix[1][1] = (float)Math.Cos( angle );
  748.                     break;
  749.  
  750.             }
  751.  
  752.             // Rotate Main matrix
  753.             Multiply( rotationMatrix, MatrixOrder.Prepend, true );
  754.        
  755.         }
  756.  
  757.         /// <summary>
  758.         /// Returns transformed x and y values from x, y and z values
  759.         /// and composed main matrix values (All rotations,
  760.         /// translations and scaling).
  761.         /// </summary>
  762.         /// <param name="points">Array of 3D points.</param>
  763.         private void GetValues( Point3D [] points )
  764.         {
  765.             // Create one dimensional matrix (vector)
  766.             float [] inputVector = new float[4];
  767.  
  768.             // A vector which is result of matrix and vector multiplication
  769.             float [] resultVector = new float[4];
  770.        
  771.             foreach( Point3D point in points )
  772.             {
  773.                 // Fill input vector with x, y and z coordinates
  774.                 inputVector[0] = point.X;
  775.                 inputVector[1] = point.Y;
  776.                 inputVector[2] = point.Z;
  777.                 inputVector[3] = 1;
  778.        
  779.                 // Apply 3D transformations.
  780.                 MultiplyVector( inputVector, ref resultVector );
  781.  
  782.                 // Return x and y coordinates.
  783.                 point.X = resultVector[0];
  784.                 point.Y = resultVector[1];
  785.                 point.Z = resultVector[2];
  786.             }
  787.         }
  788.  
  789.  
  790.         /// <summary>
  791.         /// Set points for 3D Bar which represents 3D Chart Area.
  792.         /// </summary>
  793.         /// <param name="dx">Width of the bar 3D.</param>
  794.         /// <param name="dy">Height of the bar 3D.</param>
  795.         /// <param name="dz">Depth of the bar 3D.</param>
  796.         /// <returns>Collection of Points 3D.</returns>
  797.         private Point3D [] Set3DBarPoints( float dx, float dy, float dz )
  798.         {
  799.             Point3D [] points = new Point3D[8];
  800.  
  801.             // ********************************************
  802.             // 3D Bar side: Front
  803.             // ********************************************
  804.             points[0] = new Point3D(-dx/2, -dy/2, dz/2);
  805.             points[1] = new Point3D(dx/2, -dy/2, dz/2);
  806.             points[2] = new Point3D(dx/2, dy/2, dz/2);
  807.             points[3] = new Point3D(-dx/2, dy/2, dz/2);
  808.            
  809.             // ********************************************
  810.             // 3D Bar side: Back
  811.             // ********************************************
  812.             points[4] = new Point3D(-dx/2, -dy/2, -dz/2);
  813.             points[5] = new Point3D(dx/2, -dy/2, -dz/2);
  814.             points[6] = new Point3D(dx/2, dy/2, -dz/2);
  815.             points[7] = new Point3D(-dx/2, dy/2, -dz/2);
  816.  
  817.             return points;
  818.         }
  819.  
  820.         #endregion // Private Methods
  821.        
  822.         #region Lighting Methods
  823.  
  824.         /// <summary>
  825.         /// Initial Lighting. Use matrix transformation only once
  826.         /// for Normal vectors.
  827.         /// </summary>
  828.         /// <param name="lightStyle">LightStyle Style</param>
  829.         internal void InitLight( LightStyle lightStyle )
  830.         {
  831.             // Set LightStyle Style
  832.             this._lightStyle = lightStyle;
  833.                                        
  834.             // Center of rotation
  835.             _lightVectors[0] = new Point3D( 0F, 0F, 0F );
  836.  
  837.             // Front side normal Vector.
  838.             _lightVectors[1] = new Point3D( 0F, 0F, 1F );
  839.  
  840.             // Back side normal Vector.
  841.             _lightVectors[2] = new Point3D( 0F, 0F, -1F );
  842.  
  843.             // Left side normal Vector.
  844.             _lightVectors[3] = new Point3D( -1F, 0F, 0F );
  845.  
  846.             // Right side normal Vector.
  847.             _lightVectors[4] = new Point3D( 1F, 0F, 0F );
  848.  
  849.             // Top side normal Vector.
  850.             _lightVectors[5] = new Point3D( 0F, -1F, 0F );
  851.  
  852.             // Bottom side normal Vector.
  853.             _lightVectors[6] = new Point3D( 0F, 1F, 0F );
  854.  
  855.             // Apply matrix transformations
  856.             TransformPoints( _lightVectors, false );
  857.  
  858.             // ********************************************************
  859.             // LightStyle Vector and normal vectors have to have same center.
  860.             // Shift Normal vectors.
  861.             // ********************************************************
  862.  
  863.             // Front Side shift
  864.             _lightVectors[1].X -= _lightVectors[0].X;
  865.             _lightVectors[1].Y -= _lightVectors[0].Y;
  866.             _lightVectors[1].Z -= _lightVectors[0].Z;
  867.  
  868.             // Back Side shift
  869.             _lightVectors[2].X -= _lightVectors[0].X;
  870.             _lightVectors[2].Y -= _lightVectors[0].Y;
  871.             _lightVectors[2].Z -= _lightVectors[0].Z;
  872.  
  873.             // Left Side shift
  874.             _lightVectors[3].X -= _lightVectors[0].X;
  875.             _lightVectors[3].Y -= _lightVectors[0].Y;
  876.             _lightVectors[3].Z -= _lightVectors[0].Z;
  877.  
  878.             // Right Side shift
  879.             _lightVectors[4].X -= _lightVectors[0].X;
  880.             _lightVectors[4].Y -= _lightVectors[0].Y;
  881.             _lightVectors[4].Z -= _lightVectors[0].Z;
  882.  
  883.             // Top Side shift
  884.             _lightVectors[5].X -= _lightVectors[0].X;
  885.             _lightVectors[5].Y -= _lightVectors[0].Y;
  886.             _lightVectors[5].Z -= _lightVectors[0].Z;
  887.  
  888.             // Bottom Side shift
  889.             _lightVectors[6].X -= _lightVectors[0].X;
  890.             _lightVectors[6].Y -= _lightVectors[0].Y;
  891.             _lightVectors[6].Z -= _lightVectors[0].Z;
  892.  
  893.         }
  894.  
  895.         /// <summary>
  896.         /// Return intensity of lightStyle for 3D Cube. There are tree types of lights: None,
  897.         /// Simplistic and Realistic. None Style have same lightStyle intensity on
  898.         /// all polygons. Normal vector doesn’t have influence on this type
  899.         /// of lighting. Simplistic style have lightStyle source, which is
  900.         /// rotated together with scene. Realistic lighting have fixed lightStyle
  901.         /// source and intensity of lightStyle is change when scene is rotated.
  902.         /// </summary>
  903.         /// <param name="surfaceColor">Color used for polygons without lighting</param>
  904.         /// <param name="front">Color corrected with intensity of lightStyle for Front side of the 3D Rectangle</param>
  905.         /// <param name="back">Color corrected with intensity of lightStyle for Back side of the 3D Rectangle</param>
  906.         /// <param name="left">Color corrected with intensity of lightStyle for Left side of the 3D Rectangle</param>
  907.         /// <param name="right">Color corrected with intensity of lightStyle for Right side of the 3D Rectangle</param>
  908.         /// <param name="top">Color corrected with intensity of lightStyle for Top side of the 3D Rectangle</param>
  909.         /// <param name="bottom">Color corrected with intensity of lightStyle for Bottom side of the 3D Rectangle</param>
  910.         internal void GetLight( Color surfaceColor, out Color front, out Color back, out Color left, out Color right, out Color top, out Color bottom )
  911.         {
  912.             switch( _lightStyle )
  913.             {
  914.                 // LightStyle style is None
  915.                 case  LightStyle.None:
  916.                 {
  917.                     front = surfaceColor;
  918.                     left = surfaceColor;
  919.                     top = surfaceColor;
  920.                     back = surfaceColor;
  921.                     right = surfaceColor;
  922.                     bottom = surfaceColor;
  923.                     break;
  924.                 }
  925.                 // LightStyle style is Simplistic
  926.                 case  LightStyle.Simplistic:
  927.                 {
  928.                     front = surfaceColor;
  929.                     left = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.25);
  930.                     top = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.15);
  931.                     back = surfaceColor;
  932.                     right = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.25);
  933.                     bottom = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.15);
  934.                     break;
  935.                 }
  936.                 // LightStyle style is Realistic
  937.                 default:
  938.                 {
  939.                                        
  940.                     // For Right Axis angle Realistic lightStyle should be different
  941.                     if( _rightAngleAxis )
  942.                     {
  943.                         // LightStyle source Vector
  944.                         Point3D lightSource = new Point3D( 0F, 0F, -1F );
  945.                         Point3D [] rightPRpoints = new Point3D[1];
  946.                         rightPRpoints[0] = lightSource;
  947.                         RightAngleProjection(rightPRpoints);
  948.  
  949.                         // ******************************************************************
  950.                         // Color correction. Angle between Normal vector of polygon and
  951.                         // vector of lightStyle source is used.
  952.                         // ******************************************************************
  953.                         if( this._angleY >= 45 || this._angleY <= -45 )
  954.                         {
  955.                             front = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, GetAngle(lightSource,_lightVectors[1])/Math.PI );
  956.  
  957.                             back = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, GetAngle(lightSource,_lightVectors[2])/Math.PI );
  958.                            
  959.                             left = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0 );
  960.  
  961.                             right = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0 );
  962.                         }
  963.                         else
  964.                         {
  965.                             front = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0 );
  966.  
  967.                             back = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 1 );
  968.  
  969.                             left = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, GetAngle(lightSource,_lightVectors[3])/Math.PI );
  970.  
  971.                             right = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, GetAngle(lightSource,_lightVectors[4])/Math.PI );
  972.                         }
  973.            
  974.                         top = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, GetAngle(lightSource,_lightVectors[5])/Math.PI );
  975.  
  976.                         bottom = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, GetAngle(lightSource,_lightVectors[6])/Math.PI );
  977.                     }
  978.                     else
  979.                     {
  980.                         // LightStyle source Vector
  981.                         Point3D lightSource = new Point3D( 0F, 0F, 1F );
  982.  
  983.                         // ******************************************************************
  984.                         // Color correction. Angle between Normal vector of polygon and
  985.                         // vector of lightStyle source is used.
  986.                         // ******************************************************************
  987.                         front = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[1])/Math.PI );
  988.  
  989.                         back = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[2])/Math.PI );
  990.  
  991.                         left = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[3])/Math.PI );
  992.  
  993.                         right = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[4])/Math.PI );
  994.            
  995.                         top = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[5])/Math.PI );
  996.  
  997.                         bottom = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[6])/Math.PI );
  998.                     }
  999.  
  1000.                     break;
  1001.                 }
  1002.             }
  1003.         }
  1004.        
  1005.  
  1006.         /// <summary>
  1007.         /// Return intensity of lightStyle for Polygons. There are tree types of lights: None,
  1008.         /// Simplistic and Realistic. None Style have same lightStyle intensity on
  1009.         /// all polygons. Normal vector doesn’t have influence on this type
  1010.         /// of lighting. Simplistic style have lightStyle source, which is
  1011.         /// rotated together with scene. Realistic lighting have fixed lightStyle
  1012.         /// source and intensity of lightStyle is change when scene is rotated.
  1013.         /// </summary>
  1014.         /// <param name="points">Points of the polygon</param>
  1015.         /// <param name="surfaceColor">Color used for polygons without lighting</param>
  1016.         /// <param name="visiblePolygon">This flag gets information if  polygon is visible or not.</param>
  1017.         /// <param name="rotation">Y angle ( from -90 to 90 ) Should be used width switchSeriesOrder to get from -180 to 180</param>
  1018.         /// <param name="surfaceName">Used for lighting of front - back and left - right sides</param>
  1019.         /// <param name="switchSeriesOrder">Used to calculate real y angle</param>
  1020.         /// <returns>Color corrected with intensity of lightStyle</returns>
  1021.         internal Color GetPolygonLight(Point3D[] points, Color surfaceColor, bool visiblePolygon, float rotation, SurfaceNames surfaceName, bool switchSeriesOrder)
  1022.         {
  1023.             // Corrected color
  1024.             Color color = surfaceColor;
  1025.  
  1026.             // Direction of lightStyle source
  1027.             Point3D lightSource;
  1028.             lightSource = new Point3D( 0F, 0F, 1F );
  1029.  
  1030.             // There are tree different lightStyle styles: None, Simplistic and realistic.
  1031.             switch( _lightStyle )
  1032.             {
  1033.                 // LightStyle style is None
  1034.                 case  LightStyle.None:
  1035.                 {
  1036.                     // Use same color
  1037.                     break;
  1038.                 }
  1039.                 // LightStyle style is Simplistic
  1040.                 case  LightStyle.Simplistic:
  1041.                 {
  1042.                     // Find two vectors of polygon
  1043.                     Point3D firstVector = new Point3D();
  1044.                     firstVector.X = points[0].X - points[1].X;
  1045.                     firstVector.Y = points[0].Y - points[1].Y;
  1046.                     firstVector.Z = points[0].Z - points[1].Z;
  1047.  
  1048.                     Point3D secondVector = new Point3D();
  1049.                     secondVector.X = points[2].X - points[1].X;
  1050.                     secondVector.Y = points[2].Y - points[1].Y;
  1051.                     secondVector.Z = points[2].Z - points[1].Z;
  1052.  
  1053.                     // Find Normal vector for Polygon
  1054.                     Point3D normalVector = new Point3D();
  1055.                     normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y;
  1056.                     normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z;
  1057.                     normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X;
  1058.                    
  1059.                     // Polygon is left side ( like side of area chart )
  1060.                     if( surfaceName == SurfaceNames.Left )
  1061.                     {
  1062.                         color = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.15);
  1063.                     }
  1064.                     // Polygon is right side ( like side of area chart )
  1065.                     else if( surfaceName == SurfaceNames.Right )
  1066.                     {
  1067.                         color = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.15);
  1068.                     }
  1069.                     // Polygon is front side ( like side of area chart )
  1070.                     else if( surfaceName == SurfaceNames.Front )
  1071.                     {
  1072.                         color = surfaceColor;
  1073.                     }
  1074.                     // Polygon is back side ( like side of area chart )
  1075.                     else if( surfaceName == SurfaceNames.Back )
  1076.                     {
  1077.                         color = surfaceColor;
  1078.                     }
  1079.                     // Polygon has angle with bottom side ( Line chart or top of area chart )
  1080.                     else
  1081.                     {
  1082.                         float angleLeft;
  1083.                         float angleRight;
  1084.  
  1085.                         // Find angles between lightStyle and polygon for different y-axis angles.
  1086.                         if( switchSeriesOrder )
  1087.                         {
  1088.                             if (rotation > 0 && rotation <= 90)
  1089.                             {
  1090.                                 angleLeft = GetAngle( normalVector, _lightVectors[3] );
  1091.                                 angleRight = GetAngle( normalVector, _lightVectors[4] );
  1092.                             }
  1093.                             else
  1094.                             {
  1095.                                 angleLeft = GetAngle( normalVector, _lightVectors[4] );
  1096.                                 angleRight = GetAngle( normalVector, _lightVectors[3] );
  1097.                             }
  1098.                         }
  1099.                         else
  1100.                         {
  1101.                             if (rotation > 0 && rotation <= 90)
  1102.                             {
  1103.                                 angleLeft = GetAngle( normalVector, _lightVectors[4] );
  1104.                                 angleRight = GetAngle( normalVector, _lightVectors[3] );
  1105.                             }
  1106.                             else
  1107.                             {
  1108.                                 angleLeft = GetAngle( normalVector, _lightVectors[3] );
  1109.                                 angleRight = GetAngle( normalVector, _lightVectors[4] );
  1110.                             }
  1111.                         }
  1112.  
  1113.                         if( Math.Abs( angleLeft - angleRight ) < 0.01 )
  1114.                         {
  1115.                             color = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.25);
  1116.                         }
  1117.                         else if( angleLeft < angleRight )
  1118.                         {
  1119.                             color = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.25);
  1120.                         }
  1121.                         else
  1122.                         {
  1123.                             color = ChartGraphics.GetGradientColor( surfaceColor, Color.Black, 0.15);
  1124.                         }
  1125.                     }
  1126.  
  1127.                     break;
  1128.                 }
  1129.                 // LightStyle style is Realistic
  1130.                 default:
  1131.                 {
  1132.  
  1133.                     // Find two vectors of polygon
  1134.                     Point3D firstVector = new Point3D();
  1135.                     firstVector.X = points[0].X - points[1].X;
  1136.                     firstVector.Y = points[0].Y - points[1].Y;
  1137.                     firstVector.Z = points[0].Z - points[1].Z;
  1138.  
  1139.                     Point3D secondVector = new Point3D();
  1140.                     secondVector.X = points[2].X - points[1].X;
  1141.                     secondVector.Y = points[2].Y - points[1].Y;
  1142.                     secondVector.Z = points[2].Z - points[1].Z;
  1143.  
  1144.                     // Find Normal vector for Polygon
  1145.                     Point3D normalVector = new Point3D();
  1146.                     normalVector.X = firstVector.Y * secondVector.Z - firstVector.Z * secondVector.Y;
  1147.                     normalVector.Y = firstVector.Z * secondVector.X - firstVector.X * secondVector.Z;
  1148.                     normalVector.Z = firstVector.X * secondVector.Y - firstVector.Y * secondVector.X;
  1149.  
  1150.                     // ******************************************************************
  1151.                     // Color correction. Angle between Normal vector of polygon and
  1152.                     // vector of lightStyle source is used.
  1153.                     // ******************************************************************
  1154.                     if( surfaceName == SurfaceNames.Front )
  1155.                     {
  1156.                         lightSource.Z *= -1;
  1157.                         color = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[2])/Math.PI );
  1158.                     }
  1159.                     else if( surfaceName == SurfaceNames.Back )
  1160.                     {
  1161.                         lightSource.Z *= -1;
  1162.                         color = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,_lightVectors[1])/Math.PI );
  1163.                     }
  1164.                     else
  1165.                     {
  1166.                         if( visiblePolygon )
  1167.                         {
  1168.                             lightSource.Z *= -1;
  1169.                         }
  1170.  
  1171.                         color = GetBrightGradientColor( surfaceColor, GetAngle(lightSource,normalVector)/Math.PI );
  1172.                     }
  1173.  
  1174.                     break;
  1175.                 }
  1176.             }
  1177.             return color;
  1178.            
  1179.         }
  1180.  
  1181.         /// <summary>
  1182.         /// This method creates gradien color with brightnes.
  1183.         /// </summary>
  1184.         /// <param name="beginColor">Start color for gradient.</param>
  1185.         /// <param name="position">Position used between Start and end color.</param>
  1186.         /// <returns>Calculated Gradient color from gradient position</returns>
  1187.         private Color GetBrightGradientColor( Color beginColor, double position )
  1188.         {
  1189.             position = position * 2;
  1190.             double brightness = 0.5;
  1191.             if( position < brightness )
  1192.             {
  1193.                 return ChartGraphics.GetGradientColor( Color.FromArgb(beginColor.A,255,255,255), beginColor, 1 - brightness + position );
  1194.             }
  1195.             else if( -brightness + position < 1 )
  1196.             {
  1197.                 return ChartGraphics.GetGradientColor( beginColor, Color.Black, -brightness + position );
  1198.             }
  1199.             else
  1200.             {
  1201.                 return Color.FromArgb( beginColor.A, 0, 0, 0 );
  1202.             }
  1203.         }
  1204.  
  1205.         /// <summary>
  1206.         /// Returns the angle between two 3D vectors (a and b);
  1207.         /// </summary>
  1208.         /// <param name="a">First vector</param>
  1209.         /// <param name="b">Second Vector</param>
  1210.         /// <returns>Angle between vectors</returns>
  1211.         private float GetAngle(Point3D a,Point3D b)
  1212.         {
  1213.             double angle;
  1214.  
  1215.             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 ) ) );
  1216.  
  1217.             return (float)angle;
  1218.         }
  1219.  
  1220.         #endregion
  1221.     }
  1222. }
  1223.  
  1224. [Document Outline] [Project Explorer] [Namespace Explorer]
Add Comment
Please, Sign In to add comment