/// <summary> /// This method is called when rendering is required. /// </summary> /// <param name="drawingContext"></param> protected override void OnRender(DrawingContext drawingContext) { if (!Initializing) { // Update the CAmera position persptCamera.LookDirection = cameraLookDirection; persptCamera.Position = cameraPosition; // If the user's mouse is on one of the 3D bar. then enhance the bar and display its values. if (null != SelectedHit && (PrevSelectedHit == null || 0 != PrevSelectedHit.StringToDisplay.CompareTo(SelectedHit.StringToDisplay))) { if (geometryForHitText != null) { geometryForHitText = null; modelForHitText.Content = null; mainViewPort.Children.Remove(modelForHitText); } if (modelsForHitTest != null) { List<ModelVisual3D>.Enumerator enumModelsI = modelsForHitTest.GetEnumerator(); while (enumModelsI.MoveNext()) { mainViewPort.Children.Remove(enumModelsI.Current); } } LetterLengthForHitText = SelectedHit.StringToDisplay.Length * OneLetterWidthForHitText; Point3D ptToWRite = SelectedHit.P2; ptToWRite.Y += LITTLE_ABOVE; geometryForHitText = WriteText(SelectedHit.PointToWrite, LetterLengthForHitText, OneLetterHeightForHitText, SelectedHit.StringToDisplay, Colors.Black); modelsForHitTest = Draw3DBar(SelectedHit.XItem, SelectedHit.YItem, SelectedHit.ZItem, SelectedHit.PointToStart, SelectedHit.Height, SelectedHit.Width , SelectedHit.BarColor); List<ModelVisual3D>.Enumerator enumModels = modelsForHitTest.GetEnumerator(); while (enumModels.MoveNext()) { mainViewPort.Children.Add(enumModels.Current); } PrevSelectedHit = SelectedHit; modelForHitText.Content = geometryForHitText; mainViewPort.Children.Add(modelForHitText); } // Else if there is no bar selected remove the enhancement and Hit text. else if (null == SelectedHit) { geometryForHitText = null; modelForHitText.Content = null; mainViewPort.Children.Remove(modelForHitText); if (modelsForHitTest != null) { List<ModelVisual3D>.Enumerator enumModels = modelsForHitTest.GetEnumerator(); while (enumModels.MoveNext()) { mainViewPort.Children.Remove(enumModels.Current); } } } } base.OnRender(drawingContext); }
/// <summary> /// This method is called during initialization to create the 3D Bar chart and then its called to update /// </summary> private void Initialize() { if (chartSize.Height == 0 || chartSize.Width == 0) return; Initializing = true; cameraDistance = 160 + 5 * ZItems.Length + 140 / XItems.Length; // We clear the 3D drawings, if any previously added mainViewPort.Children.Clear(); if (HideChart == true) return; mainViewPort.Children.Add(lightModelVisual); listOfHitPoints.Clear(); this.InvalidateVisual(); List<ModelVisual3D> retValue; List<ModelVisual3D>.Enumerator enumList; SelectedHit = null; modelForHitText = new ModelVisual3D(); OneLetterWidthForHitText = 1.1; OneLetterHeightForHitText = 1.7; PointToWrite0 = new Point3D(); PointToWrite1 = new Point3D(); PointToWrite2 = new Point3D(); PointToWrite3 = new Point3D(); yPlane2DPoint0 = new Point(0, 1); yPlane2DPoint1 = new Point(1, 1); yPlane2DPoint2 = new Point(1, 0); yPlane2DPoint3 = new Point(0, 0); // We draw 3D cart here. retValue = Draw3DChart(XItems, YItems, ZItems, Colors.Yellow, Colors.Cyan, ZPlaneColors, chartSize.Width/(XItems.Length * 2.2 * 10)); enumList = retValue.GetEnumerator(); // Add the resultant geometry to the main viewport. while (enumList.MoveNext()) { mainViewPort.Children.Add(enumList.Current); } retValue.Clear(); // Compute the camera position. ComputeCameraPosition(); Initializing = false; // Display the graph this.InvalidateVisual(); }
/// <summary> /// This method is called when the mouse is moved. /// </summary> /// <param name="sender"></param> /// <param name="me"></param> private void OnMouseMove(object sender, MouseEventArgs me) { if (me.LeftButton == MouseButtonState.Pressed && leftButtonDown == true) { // If the left mouse button is pressed, then we calculate the Camera position, // then invalidate the current drawing for a redraw me.MouseDevice.SetCursor(Cursors.ScrollAll); Point retPoint = me.GetPosition(pThis); double MouseX = retPoint.X; double MouseY = retPoint.Y; if (MouseX == MouseXFirstDown && MouseY == MouseYFirstDown) { return; } // To calculate how much the mouse moved X position if (MouseXFirstDown != MouseX) { XAngle += (MouseX - MouseXFirstDown) / MouseSens; MouseXFirstDown = MouseX; } // To calculate how much the mouse mofed Y position if (MouseYFirstDown != MouseY) { YAngle += (MouseY - MouseYFirstDown) / MouseSens; MouseYFirstDown = MouseY; } //ZCameraPosition = -2.5 + (-1) * cameraDistance * Math.Cos(XAngle * 3.141 / 180.0) * Math.Sin(YAngle * 3.141 / 180.0); //XCameraPosition = 2.5 + cameraDistance * Math.Sin(XAngle * 3.141 / 180.0) * Math.Sin(YAngle * 3.141 / 180.0); //YCameraPosition = 2.5 + cameraDistance * Math.Cos(YAngle * 3.141 / 180.0); ComputeCameraPosition(); SelectedHit = null; } else { Point pt = me.GetPosition((UIElement)sender); HitTestResult result = VisualTreeHelper.HitTest(mainGrid, pt); // If there is a hit, then draw the bar slightly bigger and display the Hit text // (as we stored thia already while drawing if (result != null) { RayHitTestResult res = result as RayHitTestResult; if (res != null) { GeometryModel3D geoMod = res.ModelHit as GeometryModel3D; HitDetails myHitDetails; if (listOfHitPoints.TryGetValue(geoMod, out myHitDetails)) { me.MouseDevice.SetCursor(Cursors.Hand); SelectedHit = myHitDetails; SelectedHit.ShowValue = false; this.InvalidateVisual(); return; } } } SelectedHit = null; } this.InvalidateVisual(); }
/// <summary> /// This methods draws 3D bars getting X,Y,Z values, Point to start, height, width and BarColor. /// </summary> /// <param name="XItem"></param> /// <param name="YItem"></param> /// <param name="ZItem"></param> /// <param name="PointToStart"></param> /// <param name="Height"></param> /// <param name="Width"></param> /// <param name="BarColor"></param> /// <returns></returns> private List<ModelVisual3D> Draw3DBar( string XItem, string YItem, string ZItem, Point3D PointToStart, double Height, double Width, Color BarColor) { ////////////////////////////////////////////////////////////////////////////////////////////////////////// // This method first calculates the 8 points P0 to P7 required to draw the bar. Then it calculates // // the points to write the Hit Text. I.e., when the bar is hit by a hovering mouse, we need to // // display the X,Y,Z values for that bar. So this point P00 to P33 is calculated to draw the text // // during hit text. We store this information in a seperate class called HitDetails with the geometry // // as the hit key. Then we draw the bars using the DrawRect method. // ////////////////////////////////////////////////////////////////////////////////////////////////////////// modelArray = new List<ModelVisual3D>(); // Points are calculated to draw the bar Point3D P0 = new Point3D(PointToStart.X, PointToStart.Y, PointToStart.Z); Point3D P1 = new Point3D(PointToStart.X + Width, PointToStart.Y, PointToStart.Z); Point3D P2 = new Point3D(PointToStart.X + Width, PointToStart.Y, PointToStart.Z - Width); Point3D P3 = new Point3D(PointToStart.X, PointToStart.Y, PointToStart.Z - Width); Point3D P4 = new Point3D(PointToStart.X, PointToStart.Y + Height, PointToStart.Z); Point3D P5 = new Point3D(PointToStart.X + Width, PointToStart.Y + Height, PointToStart.Z); Point3D P6 = new Point3D(PointToStart.X + Width, PointToStart.Y + Height, PointToStart.Z - Width); Point3D P7 = new Point3D(PointToStart.X, PointToStart.Y + Height, PointToStart.Z - Width); ModelVisual3D myModelVisual = new ModelVisual3D(); Model3DGroup myModelGroup = new Model3DGroup(); // Points are calculated to draw the hit text and hit line Point3D P00 = new Point3D(xStartingPoint, P4.Y + 0.3, P4.Z - Width / 2.0); Point3D P11 = new Point3D(P4.X, P4.Y + 0.3, P4.Z - Width / 2.0); Point3D P22 = new Point3D(P4.X, P4.Y, P4.Z - Width / 2.0 - 0.3); Point3D P33 = new Point3D(xStartingPoint, P4.Y, P4.Z - Width / 2.0 - 0.3); Point3D PtToWrite = new Point3D(P4.X, P4.Y + LITTLE_ABOVE, P4.Z + Width / 2.0 - 0.3); HitDetails newHitDetails = new HitDetails(XItem, YItem, ZItem, P00, P11, P22, P33, PtToWrite, PointToStart, Width, Height, BarColor); GeometryModel3D rectVisual = DrawRect(P0, P1, P5, P4, BarColor, DEFAULT_BRUSH_OPACITY); listOfHitPoints.Add(rectVisual, newHitDetails); myModelGroup.Children.Add(rectVisual); // Lets draw the rectangles that form a full bar convering its top and bottom Color LightColor = BarColor; LightColor.A -= DROP_COLOR_BRIGHTNESS; rectVisual = DrawRect(P1, P2, P6, P5, LightColor, DEFAULT_BAR_OPACITY); listOfHitPoints.Add(rectVisual, newHitDetails); myModelGroup.Children.Add(rectVisual); rectVisual = DrawRect(P3, P2, P6, P7, BarColor, DEFAULT_BAR_OPACITY); listOfHitPoints.Add(rectVisual, newHitDetails); myModelGroup.Children.Add(rectVisual); rectVisual = DrawRect(P0, P3, P7, P4, LightColor, DEFAULT_BAR_OPACITY); listOfHitPoints.Add(rectVisual, newHitDetails); myModelGroup.Children.Add(rectVisual); LightColor.A -= DROP_MORE_COLOR_BRIGHTNESS; rectVisual = DrawRect(P4, P5, P6, P7, LightColor, DEFAULT_BRUSH_OPACITY); listOfHitPoints.Add(rectVisual, newHitDetails); myModelGroup.Children.Add(rectVisual); rectVisual = DrawRect(P0, P1, P2, P3, BarColor, DEFAULT_BRUSH_OPACITY); listOfHitPoints.Add(rectVisual, newHitDetails); myModelGroup.Children.Add(rectVisual); myModelVisual.Content = myModelGroup; modelArray.Add(myModelVisual); // return the model to be added to the main ViewPort3D return modelArray; }