public VelocityVisualizer3DWindow() { InitializeComponent(); // Camera Trackball _trackball = new TrackBallRoam(_camera); _trackball.EventSource = grdViewPort; //NOTE: If this control doesn't have a background color set, the trackball won't see events (I think transparent is ok, just not null) _trackball.AllowZoomOnMouseWheel = true; _trackball.MouseWheelScale *= .1d; _trackball.Mappings.AddRange(TrackBallMapping.GetPrebuilt(TrackBallMapping.PrebuiltMapping.MouseComplete)); //_trackball.GetOrbitRadius += new GetOrbitRadiusHandler(Trackball_GetOrbitRadius); // Velocity line visual _velocityLines = new BillboardLine3DSet(); _velocityLines.Color = Colors.GhostWhite; _velocityLines.IsReflectiveColor = true; _viewport.Children.Add(_velocityLines); UpdateLinePlacement(); ShowHideBlockedCells(); }
private void AddLines_Billboard(IEnumerable<Tuple<int, int>> lines, Point3D[] points, double thickness, Color color) { BillboardLine3DSet visual = new BillboardLine3DSet(); visual.Color = color; visual.BeginAddingLines(); foreach (Tuple<int, int> line in lines) { visual.AddLine(points[line.Item1], points[line.Item2], thickness); } visual.EndAddingLines(); _viewport.Children.Add(visual); _visuals.Add(visual); }
private void Window_Closed(object sender, EventArgs e) { try { if (_velocityLines != null) { _velocityLines.Dispose(); _velocityLines = null; } } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
private static void AddPolyLines(BillboardLine3DSet lines, Point3D[] polygon, double thickness) { for (int cntr = 0; cntr < polygon.Length - 1; cntr++) { lines.AddLine(polygon[cntr], polygon[cntr + 1], thickness); } lines.AddLine(polygon[polygon.Length - 1], polygon[0], thickness); }
private void RedrawPoints() { // Clear old _viewport.Children.RemoveAll(_visuals); _visuals.Clear(); if (_points == null || _points.Length == 0) { return; } #region Points Model3DGroup geometries = new Model3DGroup(); for (int cntr = 0; cntr < _points.Length; cntr++) { Color color = UtilityWPF.AlphaBlend(Colors.Black, UtilityWPF.ColorFromHex("08000000"), _points[cntr].Value); // Material MaterialGroup materials = new MaterialGroup(); materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(color))); materials.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.AlphaBlend(color, Colors.White, .5d)), 100d)); // Geometry Model GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = materials; geometry.BackMaterial = materials; geometry.Geometry = UtilityWPF.GetSphere_LatLon(2, DOTRADIUS); geometry.Transform = new TranslateTransform3D(_points[cntr].Point.ToVector3D()); geometries.Children.Add(geometry); } ModelVisual3D visual = new ModelVisual3D(); visual.Content = geometries; _visuals.Add(visual); _viewport.Children.Add(visual); #endregion if (radShowTriangles1.IsChecked.Value || radShowTriangles2.IsChecked.Value || radShowContour.IsChecked.Value || radShowContourAndTriangles.IsChecked.Value) { #region Height Triangles, Contour //var triangles = Math2D.GetDelaunayTriangulation(_points.Select(o => o.Point).ToArray(), _points.Select(o => o.Point.ToPoint3D() + new Vector3D(0, 0, o.Value * trkTriangleHeight.Value)).ToArray()); var triangles = GetDelaunay_ExpandRing(_points, trkTriangleHeight.Value); if (radShowTriangles1.IsChecked.Value || radShowContourAndTriangles.IsChecked.Value) { #region Triangles (mono color) Color color = UtilityWPF.ColorFromHex("40808080"); // Material MaterialGroup materials = new MaterialGroup(); materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(color))); materials.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.AlphaBlend(UtilityWPF.AlphaBlend(color, Colors.White, .5d), Colors.Transparent, .25d)), 5d)); // Geometry Model GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = materials; geometry.BackMaterial = materials; geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(triangles.Item2); visual = new ModelVisual3D(); visual.Content = geometry; _visuals.Add(visual); _viewport.Children.Add(visual); #endregion } else if (radShowTriangles2.IsChecked.Value) { #region Triangles (height color) geometries = new Model3DGroup(); foreach (var triangle in triangles.Item2) { double averageHeight = Math1D.Avg(triangles.Item1[triangle.Index0].Value, triangles.Item1[triangle.Index1].Value, triangles.Item1[triangle.Index2].Value); Color color = UtilityWPF.AlphaBlend(Colors.Black, Colors.White, averageHeight); // Material Material material = UtilityWPF.GetUnlitMaterial(Color.FromArgb(192, color.R, color.G, color.B)); // Don't want reflection, it will just confuse the coloring // Geometry Model GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = material; geometry.Geometry = UtilityWPF.GetMeshFromTriangles(new ITriangleIndexed[] { triangle }); geometries.Children.Add(geometry); } visual = new ModelVisual3D(); visual.Content = geometries; _visuals.Add(visual); _viewport.Children.Add(visual); #endregion } if (radShowContour.IsChecked.Value || radShowContourAndTriangles.IsChecked.Value) { #region Contours //TODO: Instead of just triangles, make parabola hills //var triangles = GetDelaunay_ExpandRing(_points, trkTriangleHeight.Value); int numContours = Convert.ToInt32(trkNumContours.Value); for (int cntr = 0; cntr < numContours; cntr++) { double height = Convert.ToDouble(cntr + 1) / Convert.ToDouble(numContours + 1); // one contour would be 50%, two would be 33% and 66%, etc double heightScaled = height * trkTriangleHeight.Value; var polys = Math3D.GetIntersection_Mesh_Plane(triangles.Item2, new Triangle(new Point3D(-1, 0, heightScaled), new Point3D(1, 0, heightScaled), new Point3D(0, 1, heightScaled))); if (polys != null && polys.Length > 0) { BillboardLine3DSet lines = new BillboardLine3DSet(); lines.Color = UtilityWPF.AlphaBlend(Colors.Black, Colors.White, height); lines.IsReflectiveColor = false; lines.BeginAddingLines(); for (int outer = 0; outer < polys.Length; outer++) { AddPolyLines(lines, polys[outer].Polygon3D, LINETHICKNESS); for (int inner = 0; inner < polys[outer].Holes3D.Length; inner++) { AddPolyLines(lines, polys[outer].Holes3D[inner], LINETHICKNESS); } } lines.EndAddingLines(); _visuals.Add(lines); _viewport.Children.Add(lines); } } #endregion } if (chkShowTriangleEdges.IsChecked.Value) { #region Edge Lines BillboardLine3DSet lines = new BillboardLine3DSet(); lines.Color = UtilityWPF.ColorFromHex("80808080"); lines.IsReflectiveColor = false; lines.BeginAddingLines(); Point3D[] trianglePoints = triangles.Item2[0].AllPoints; foreach (var line in TriangleIndexed.GetUniqueLines(triangles.Item2)) { lines.AddLine(trianglePoints[line.Item1], trianglePoints[line.Item2], LINETHICKNESS); } lines.EndAddingLines(); _visuals.Add(lines); _viewport.Children.Add(lines); #endregion } #endregion } else if (radShowLines.IsChecked.Value) { #region Height Lines BillboardLine3DSet lines = new BillboardLine3DSet(); lines.Color = UtilityWPF.ColorFromHex("80808080"); lines.IsReflectiveColor = false; lines.BeginAddingLines(); for (int cntr = 0; cntr < _points.Length; cntr++) { lines.AddLine(_points[cntr].Point.ToPoint3D(), _points[cntr].Point.ToPoint3D() + new Vector3D(0, 0, _points[cntr].Value * trkTriangleHeight.Value), LINETHICKNESS); } lines.EndAddingLines(); _visuals.Add(lines); _viewport.Children.Add(lines); #endregion } }
private void btnContour_Click(object sender, RoutedEventArgs e) { try { RedrawPoints(); if (_points == null || _points.Length == 0) { return; } #region Get terrain triangles // Cut a contour slice at the height of trkContourTestHeight var triangles = GetDelaunay_ExpandRing(_points, trkTriangleHeight.Value); List<TriangleIndexedLinked> trianglesLinked = triangles.Item2.Select(o => new TriangleIndexedLinked(o.Index0, o.Index1, o.Index2, o.AllPoints)).ToList(); TriangleIndexedLinked.LinkTriangles_Edges(trianglesLinked, true); #endregion int contourCount = Convert.ToInt32(trkContourTestCount.Value); double minHeight = trkContourTestHeight.Value; double maxHeight = 1; if (chkContourTestHeightIsPercent.IsChecked.Value) { double maxValue = _points.Max(o => o.Value); minHeight *= maxValue; maxHeight *= maxValue; } double heightStep = (maxHeight - minHeight) / Convert.ToDouble(contourCount); for (int contourCntr = 0; contourCntr < contourCount; contourCntr++) { double height = minHeight + (heightStep * contourCntr); double heightScaled = height * trkTriangleHeight.Value; Triangle plane = new Triangle(new Point3D(-1, 0, heightScaled), new Point3D(1, 0, heightScaled), new Point3D(0, 1, heightScaled)); // normal needs to point up // Get the contour polygons var polys = Math3D.GetIntersection_Mesh_Plane(trianglesLinked.ToArray(), plane); if (polys == null || polys.Length == 0) { return; } #region Get area, volume var densities = polys.Select(o => { double area = Math2D.GetAreaPolygon(o.Polygon2D); foreach (Point[] hole in o.Holes2D) { area -= Math2D.GetAreaPolygon(hole); } double volume = o.GetVolumeAbove(); return new { Area = area, Volume = volume, Density = volume / area }; }).ToArray(); int winnerIndexArea = 0; int winnerIndexVolume = 0; double maxArea = densities[0].Area; double maxVolume = densities[0].Volume; for (int cntr = 1; cntr < densities.Length; cntr++) { if (densities[cntr].Area > maxArea) { maxArea = densities[cntr].Area; winnerIndexArea = cntr; } if (densities[cntr].Volume > maxVolume) { maxVolume = densities[cntr].Volume; winnerIndexVolume = cntr; } } #endregion #region Draw Poly Islands BillboardLine3DSet holes = null; if (polys.Any(o => o.Holes3D.Length > 0)) { holes = new BillboardLine3DSet(); holes.Color = UtilityWPF.ColorFromHex("68BAA0BA"); holes.IsReflectiveColor = false; holes.BeginAddingLines(); } for (int cntr = 0; cntr < polys.Length; cntr++) { // Main polygon BillboardLine3DSet lines = new BillboardLine3DSet(); if (cntr == winnerIndexArea && cntr == winnerIndexVolume) { lines.Color = Color.FromRgb(192, 64, 192); } else if (cntr == winnerIndexArea) { lines.Color = Color.FromRgb(192, 64, 64); } else if (cntr == winnerIndexVolume) { lines.Color = Color.FromRgb(64, 64, 192); } else { lines.Color = UtilityWPF.GetRandomColor(255, 64, 64, 100, 200, 64, 64); } lines.IsReflectiveColor = false; lines.BeginAddingLines(); AddPolyLines(lines, polys[cntr].Polygon3D, LINETHICKNESS); // Winner Point if (cntr == winnerIndexArea || cntr == winnerIndexVolume) { Point3D polyCenter = Math3D.GetCenter(polys[cntr].Polygon3D); lines.AddLine(new Point3D(polyCenter.X, polyCenter.Y, 0), new Point3D(polyCenter.X, polyCenter.Y, RADIUS * 2), LINETHICKNESS * 2); } //// Volume //lines.AddLine(polys[cntr].Polygon3D[0], polys[cntr].Polygon3D[0] + new Vector3D(0, 0, densities[cntr].Volume * 10), LINETHICKNESS * 5); //// Area //int halfIndex = polys[cntr].Polygon3D.Length / 2; //lines.AddLine(polys[cntr].Polygon3D[halfIndex], polys[cntr].Polygon3D[halfIndex] + new Vector3D(0, 0, densities[cntr].Area * 10), LINETHICKNESS); ////Density just doesn't seem to add value. The height will attract a larger polygon, so relating volume to area doesn't make much sense //// Density //int quarterIndex = polys[cntr].Polygon3D.Length / 4; //lines.AddLine(polys[cntr].Polygon3D[quarterIndex], polys[cntr].Polygon3D[quarterIndex] + new Vector3D(0, 0, densities[cntr].Density * 10), LINETHICKNESS * 2); lines.EndAddingLines(); _visuals.Add(lines); _viewport.Children.Add(lines); // Holes foreach (Point3D[] polyHole in polys[cntr].Holes3D) { AddPolyLines(holes, polyHole, LINETHICKNESS); } } if (holes != null) { holes.EndAddingLines(); _visuals.Add(holes); _viewport.Children.Add(holes); } #endregion } } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
private static void DrawLine(Point3D position, Vector3D direction, Color color, Viewport3D viewport, List<Visual3D> debugVisuals) { BillboardLine3DSet line = new BillboardLine3DSet() { Color = color, IsReflectiveColor = false, }; line.BeginAddingLines(); line.AddLine(position, position + direction, .2); line.EndAddingLines(); debugVisuals.Add(line); viewport.Children.Add(line); }
private static Visual3D AddLines(Viewport3D viewport, IEnumerable<Tuple<Point3D, Point3D>> lines, Color color, double thickness = .015) { BillboardLine3DSet retVal = new BillboardLine3DSet(); retVal.Color = color; retVal.BeginAddingLines(); foreach (Tuple<Point3D, Point3D> line in lines) { retVal.AddLine(line.Item1, line.Item2, thickness); } retVal.EndAddingLines(); viewport.Children.Add(retVal); return retVal; }