public AddArrow ( System.Windows.Media.Media3D.Point3D point1, System.Windows.Media.Media3D.Point3D point2, double diameter, double headLength = 3, double headDiameter = 2, int thetaDiv = 18 ) : void | ||
point1 | System.Windows.Media.Media3D.Point3D | /// The start point. /// |
point2 | System.Windows.Media.Media3D.Point3D | /// The end point. /// |
diameter | double | /// The diameter of the arrow cylinder. /// |
headLength | double | /// Length of the head (relative to diameter). /// |
headDiameter | double | |
thetaDiv | int | /// The number of divisions around the arrow. /// |
Результат | void |
//// Using a DependencyProperty as the backing store for Direction. This enables animation, styling, binding, etc... //public static readonly DependencyProperty DirectionProperty = // DependencyProperty.Register("Direction", typeof(Vector3D), typeof(SensorVisual3D), new PropertyMetadata(new Vector3D(1, 0, 0), GeometryChanged)); //public string Name //{ // get { return (string)GetValue(NameProperty); } // set { SetValue(NameProperty, value); } //} //// Using a DependencyProperty as the backing store for Name. This enables animation, styling, binding, etc... //public static readonly DependencyProperty NameProperty = // DependencyProperty.Register("Name", typeof(Size3D), typeof(SensorVisual3D), new PropertyMetadata(new Size3D(), GeometryChanged)); //public Size3D Size //{ // get { return (Size3D)GetValue(SizeProperty); } // set { SetValue(SizeProperty, value); } //} //// Using a DependencyProperty as the backing store for Size. This enables animation, styling, binding, etc... //public static readonly DependencyProperty SizeProperty = // DependencyProperty.Register("Size", typeof(Size3D), typeof(SensorVisual3D), new PropertyMetadata(new Size3D(0, 0, 0), GeometryChanged)); /// <summary> /// The tessellate. /// </summary> /// <returns>The mesh.</returns> protected override MeshGeometry3D Tessellate() { var builder = new ht.MeshBuilder(true, true); builder.AddArrow(this.Position, this.Position + this.Orientation.Axis, 1); return(builder.ToMesh()); }
private void UpdateModel() { // http://en.wikipedia.org/wiki/Lorenz_attractor Func<double[], double[]> lorenzAttractor = x => { var dx = new double[3]; dx[0] = sigma * (x[1] - x[0]); dx[1] = x[0] * (rho - x[2]) - x[1]; dx[2] = x[0] * x[1] - beta * x[2]; return dx; }; // solve the ODE var x0 = new[] { 0, 1, 1.05 }; IEnumerable<double[]> solution = EulerSolver(lorenzAttractor, x0, 25); // todo: should have a better ODE solver (R-K(4,5)? http://www.mathworks.com/help/techdoc/ref/ode45.html) List<Point3D> path = solution.Select(x => new Point3D(x[0], x[1], x[2])).ToList(); // create the WPF3D model var m = new Model3DGroup(); var gm = new MeshBuilder(); gm.AddTube(path, 0.8, 10, false); if (directionArrows) { // sphere at the initial point gm.AddSphere(path[0], 1); // arrow heads every 100 point for (int i = 100; i + 1 < path.Count; i += 100) { gm.AddArrow(path[i], path[i + 1], 0.8); } // arrow head at the end Point3D p0 = path[path.Count - 2]; Point3D p1 = path[path.Count - 1]; var d = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z); d.Normalize(); Point3D p2 = p1 + d * 2; gm.AddArrow(p1, p2, 0.8); } m.Children.Add(new GeometryModel3D(gm.ToMesh(), Materials.Gold)); Model = m; }
/// <summary> /// Create the text for the north arrow. /// /// It is suggested to use an image instead /// of text for performance purposes. I will /// look into this later. /// </summary> /// <returns>3D Text.</returns> private Model3D NorthArrow(int numBins) { Model3DGroup group = new Model3DGroup(); // Get the length of the cylinder, if it is 0, then display something. double arrowLength = CylinderRadius * SCALE_ARROW; if (arrowLength <= 0) { arrowLength = SCALE_ARROW; } #region Arrow //Create the shape of the object //This will be an arrow //Length will be the scale value //The position will be above the plot double xAxisLoc = 0; double yAxisLoc = 0; double zAxisLoc = 0; if (YAxis) { yAxisLoc = -numBins * TRANSLATION_SCALE; } else { xAxisLoc = numBins * TRANSLATION_SCALE; } var mb = new MeshBuilder(false, false); if (YAxis) { mb.AddArrow(new Point3D(xAxisLoc, yAxisLoc, zAxisLoc), new Point3D(arrowLength, yAxisLoc, zAxisLoc), LABEL_ARROW_HEAD_SIZE, 3, 100); } else { mb.AddArrow(new Point3D(xAxisLoc, yAxisLoc, zAxisLoc), new Point3D(xAxisLoc, arrowLength, zAxisLoc), LABEL_ARROW_HEAD_SIZE, 3, 100); } Geometry3D geometry = mb.ToMesh(); //Set the color Material material = MaterialHelper.CreateMaterial(SELECTED_BIN_COLOR); material.Freeze(); var model = new GeometryModel3D(geometry, material); model.BackMaterial = material; #endregion #region Text double xAxisLocLabel = 0; double yAxisLocLabel = 0; double zAxisLocLabel = LABEL_ARROW_HEAD_SIZE; // Make the text just in front of the North arrow if (YAxis) { xAxisLocLabel = arrowLength / 2; // Make the text in the middle of the North arrow yAxisLocLabel = -numBins * TRANSLATION_SCALE; // Go to the bottom of the column } else { xAxisLocLabel = numBins * TRANSLATION_SCALE; yAxisLocLabel = arrowLength / 2; } TextVisual3D txt = new TextVisual3D(); txt.Position = new Point3D(xAxisLocLabel, yAxisLocLabel, zAxisLocLabel); txt.Height = 0.5; txt.Text = string.Format("North {0}", (arrowLength / SCALE_ARROW).ToString("0.0")); // Need to get the arrowLenght back to m/s txt.TextDirection = new Vector3D(1, 0, 0); // Set text to run in line with X axis txt.UpDirection = new Vector3D(0, 1, 0); // Set text to Point Up on Y axis txt.Foreground = new SolidColorBrush(Colors.Black); txt.Background = new SolidColorBrush(Colors.WhiteSmoke); txt.Padding = new Thickness(2); #endregion group.Children.Add(model); group.Children.Add(txt.Content); return group; }
/// <summary> /// Create the East and Radius label. /// This will display the text for "East" and the size /// of the cylinder radius. /// </summary> /// <param name="numBins">Number of bins in the ensemble.</param> /// <returns>Model of the label.</returns> private Model3D EastArrow(int numBins) { Model3DGroup group = new Model3DGroup(); // Get the length of the cylinder, if it is 0, then display something. double arrowLength = CylinderRadius * SCALE_ARROW; if (arrowLength <= 0) { arrowLength = SCALE_ARROW; } #region Arrow //Create the shape of the object //This will be an arrow //Length will be the scale value //The position will be above the plot double xAxisLoc = 0; double yAxisLoc = 0; double zAxisLoc = 0; if (YAxis) { yAxisLoc = -numBins * TRANSLATION_SCALE; // Go to the bottom of the column } else { xAxisLoc = numBins * TRANSLATION_SCALE; } var mb = new MeshBuilder(false, false); mb.AddArrow(new Point3D(xAxisLoc, yAxisLoc, zAxisLoc), new Point3D(xAxisLoc, yAxisLoc, arrowLength), LABEL_ARROW_HEAD_SIZE, 3, 100); Geometry3D geometry = mb.ToMesh(); //Set the color Material material = MaterialHelper.CreateMaterial(Colors.Lime); material.Freeze(); ////Rotate the object //var rotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(xAxisLoc, yAxisLoc, zAxisLoc), 90)); //rotation.Freeze(); //var tg = new Transform3DGroup(); //tg.Children.Add(rotation); var model = new GeometryModel3D(geometry, material) {}; model.BackMaterial = material; #endregion #region Text double xAxisLocLabel = 0; double yAxisLocLabel = 0; double zAxisLocLabel = 0; if (YAxis) { xAxisLocLabel = -LABEL_ARROW_HEAD_SIZE; // Make the text in the middle of the East arrow yAxisLocLabel = (-numBins * TRANSLATION_SCALE) - (ARROW_HEAD_SIZE * 2); // Go to the bottom of the column zAxisLocLabel = (arrowLength / 2); // Make the text just in front of the East arrow } else { xAxisLocLabel = (numBins * TRANSLATION_SCALE) + (ARROW_HEAD_SIZE * 2); // Go to the bottom of the column yAxisLocLabel = -(ARROW_HEAD_SIZE * 2); // Make the text just in front of the East arrow zAxisLocLabel = (arrowLength / 2); // Make the text in the middle of the East arrow } TextVisual3D txt = new TextVisual3D(); txt.Position = new Point3D(xAxisLocLabel, yAxisLocLabel, zAxisLocLabel); txt.Height = 0.5; txt.Text = string.Format("East {0}", (arrowLength / SCALE_ARROW).ToString("0.0")); txt.TextDirection = new Vector3D(0, 0, 1); // Set text to run in line with X axis txt.UpDirection = new Vector3D(0, 1, 0); // Set text to Point Up on Y axis txt.Foreground = new SolidColorBrush(Colors.Black); txt.Background = new SolidColorBrush(Colors.WhiteSmoke); txt.Padding = new Thickness(2); #endregion group.Children.Add(model); group.Children.Add(txt.Content); return group; }
/// <summary> /// Create an arrow representing the magnitude and direction /// for a given bin. This will create an arrow within a column. /// The Column will start at 0 and go down, using the bin times a scale /// factor to move down the column for each bin. The magnitude will /// give the length and color of the arrow. The angle will be used to rotate around /// the origin of 0,0, to give the direction. The angle is based off North = 0 degrees. /// </summary> /// <param name="bin">Bin to create.</param> /// <param name="mag">Magnitude of the bin.</param> /// <param name="angleYNorth">Direction of the bin with reference to Y as North.</param> /// <returns>3D model of the arrow.</returns> private GeometryModel3D CreateBin(int bin, double mag, double angleYNorth) { // Location on the axis for each bin // Set the Camera UpDirection in XMAL to UpDirection="0, 1, 0" to make it use Y axis as Up. Default is Z up. double xAxisLoc = 0; double yAxisLoc = 0; double zAxisLoc = 0; if (YAxis) { yAxisLoc = -bin * TRANSLATION_SCALE; } else { xAxisLoc = bin * TRANSLATION_SCALE; } // Create the shape of the object // This will be an arrow // Use the magnitude to get the length of the arrow // Create a column of bins with arrows var mb = new MeshBuilder(false, false); if (YAxis) { mb.AddArrow(new Point3D(xAxisLoc, yAxisLoc, zAxisLoc), new Point3D(mag * SCALE_ARROW, yAxisLoc, zAxisLoc), ARROW_HEAD_SIZE); } else { mb.AddArrow(new Point3D(xAxisLoc, yAxisLoc, zAxisLoc), new Point3D(xAxisLoc, mag * SCALE_ARROW, zAxisLoc), ARROW_HEAD_SIZE); } Geometry3D geometry = mb.ToMesh(); // Set the color based off the magnitude // If the bin is selected, use the selected color Material material; if (bin != SelectedBin) { material = MaterialHelper.CreateMaterial(GenerateColor(mag)); } else { material = MaterialHelper.CreateMaterial(SELECTED_BIN_COLOR); } material.Freeze(); // Rotate the object var rotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(xAxisLoc, yAxisLoc, zAxisLoc), angleYNorth)); rotation.Freeze(); // Create the model with the rotation var tg = new Transform3DGroup(); tg.Children.Add(rotation); var model = new GeometryModel3D(geometry, material) { Transform = tg }; return model; }
/// <summary> /// Updates the geometry. /// </summary> protected override void UpdateGeometry() { var mb = new MeshBuilder(false, false); var p0 = new Point3D(0, 0, 0); var d = this.Direction; d.Normalize(); var p1 = p0 + (d * this.Length); mb.AddArrow(p0, p1, this.Diameter); this.Model.Geometry = mb.ToMesh(); }
/// <summary> /// Updates the visuals. /// </summary> protected virtual void OnMeshChanged() { this.Children.Clear(); var builder = new MeshBuilder(); for (int i = 0; i < this.Mesh.Positions.Count; i++) { builder.AddArrow( this.Mesh.Positions[i], this.Mesh.Positions[i] + this.Mesh.Normals[i], this.Diameter, 3, 10); } this.Content = new GeometryModel3D { Geometry = builder.ToMesh(true), Material = MaterialHelper.CreateMaterial(this.Color) }; }
/// <summary> /// Do the tessellation and return the <see cref="MeshGeometry3D"/>. /// </summary> /// <returns>A triangular mesh geometry.</returns> protected override MeshGeometry3D Tessellate() { if (this.Diameter <= 0) { return null; } var builder = new MeshBuilder(true, true); builder.AddArrow(this.Point1, this.Point2, this.Diameter, this.HeadLength, this.ThetaDiv); return builder.ToMesh(); }
/// <summary> /// Updates the visuals. /// </summary> protected void UpdateVisuals() { this.vertexVisuals = new Dictionary<HalfEdgeMesh.Vertex, ModelUIElement3D>(); this.halfEdgeVisuals = new Dictionary<HalfEdgeMesh.HalfEdge, ModelUIElement3D>(); this.faceVisuals = new Dictionary<HalfEdgeMesh.Face, ModelUIElement3D>(); this.Children.Clear(); if (this.Mesh == null) { return; } if (this.VertexRadius > 0) { // Add the vertices foreach (var vertex in this.Mesh.Vertices) { var gm = new MeshBuilder(false, false); gm.AddSubdivisionSphere(vertex.Position, this.VertexRadius, 4); var vertexElement = new ModelUIElement3D { Model = new GeometryModel3D(gm.ToMesh(), this.VertexMaterial) }; var currentVertex = vertex; vertexElement.MouseLeftButtonDown += (s, e) => this.HighlightVertex(currentVertex); this.vertexVisuals.Add(vertex, vertexElement); this.Add(vertexElement); } } var faceCenter = new Dictionary<HalfEdgeMesh.Face, Point3D>(); foreach (var face in this.Mesh.Faces) { var faceVertices = face.Vertices.Select(v => v.Position).ToList(); // Find the face centroid var center = this.FindCentroid(faceVertices); faceCenter.Add(face, center); if (this.ShrinkFactor < 1) { // Add the faces for (int i = 0; i < faceVertices.Count; i++) { faceVertices[i] += (center - faceVertices[i]) * this.ShrinkFactor; } var gm = new MeshBuilder(false, false); gm.AddTriangleFan(faceVertices); var faceElement = new ModelUIElement3D { Model = new GeometryModel3D(gm.ToMesh(), this.FaceMaterial) { BackMaterial = this.FaceBackMaterial } }; var currentFace = face; faceElement.MouseLeftButtonDown += (s, e) => this.HighlightFace(currentFace); this.faceVisuals.Add(face, faceElement); this.Add(faceElement); } } if (this.EdgeDiameter > 0) { // Add the edges foreach (var edge in this.Mesh.Edges) { var start = edge.StartVertex.Position; var end = edge.EndVertex.Position; var center = faceCenter[edge.Face]; start = start + (center - start) * this.ShrinkFactor; end = end + (center - end) * this.ShrinkFactor; var gm = new MeshBuilder(false, false); gm.AddArrow(start, end, this.EdgeDiameter); var edgeElement = new ModelUIElement3D { Model = new GeometryModel3D(gm.ToMesh(), this.EdgeMaterial) }; var currentEdge = edge; edgeElement.MouseLeftButtonDown += (s, e) => { this.HighlightEdge(currentEdge); }; this.halfEdgeVisuals.Add(edge, edgeElement); this.Add(edgeElement); } } }
/// <summary> /// Add an arrow geometry object pointing up starting at (0,0,0). /// </summary> /// <param name="shapeName">The 3DView object.</param> /// <param name="length">The length of the arrow.</param> /// <param name="diameter">The diameter of the arrow shaft.</param> /// <param name="arrowLength">The length of the arrow head.</param> /// <param name="arrowDiameter">The diameter of the arrow head.</param> /// <param name="divisions">The number of divisions for the arrow (default 18).</param> /// <param name="colour">A colour or gradient brush for the object.</param> /// <param name="materialType">A material for the object. /// The available options are: /// "E" Emmissive - constant brightness. /// "D" Diffusive - affected by lights. /// "S" Specular - specular highlights. /// </param> /// <returns>The 3DView Geometry name.</returns> public static Primitive AddArrow(Primitive shapeName, Primitive length, Primitive diameter, Primitive arrowLength, Primitive arrowDiameter, Primitive divisions, Primitive colour, Primitive materialType) { UIElement obj; try { if (_objectsMap.TryGetValue((string)shapeName, out obj)) { InvokeHelperWithReturn ret = new InvokeHelperWithReturn(delegate { try { if (obj.GetType() == typeof(Viewport3D)) { MeshBuilder builder = new MeshBuilder(true, true); builder.AddArrow(new Point3D(0, 0, 0), new Point3D(0, length, 0), diameter, arrowLength / diameter, arrowDiameter / diameter, divisions); MeshGeometry3D mesh = builder.ToMesh(); Viewport3D viewport3D = (Viewport3D)obj; return AddGeometry(viewport3D, mesh.Positions, mesh.TriangleIndices, mesh.Normals, mesh.TextureCoordinates, colour, materialType); } } catch (Exception ex) { Utilities.OnError(Utilities.GetCurrentMethod(), ex); } return ""; }); return FastThread.InvokeWithReturn(ret).ToString(); } else { Utilities.OnShapeError(Utilities.GetCurrentMethod(), shapeName); } } catch (Exception ex) { Utilities.OnError(Utilities.GetCurrentMethod(), ex); } return ""; }