public void TestBaseCaseTriangle() { List <Point> triangleInPositiveOrientation = new List <Point>() { new Point(0, 0), new Point(1, 0), new Point(0, 1) }; Int32Collection indices = SweepLinePolygonTriangulator.Triangulate(triangleInPositiveOrientation); Assert.That(indices.Count == 3); Assert.That(indices[0] == 0); Assert.That(indices[1] == 1); Assert.That(indices[2] == 2); List <Point> triangleInNegativeOrientation = new List <Point>() { new Point(0, 0), new Point(0, 1), new Point(1, 0) }; indices = SweepLinePolygonTriangulator.Triangulate(triangleInNegativeOrientation); Assert.That(indices.Count == 3); Assert.That(indices[0] == 0); Assert.That(indices[1] == 2); Assert.That(indices[2] == 1); }
private static void CreateSimpleTriangulatedMesh(MeshBuilder meshBuilder) { List <Point> triangleInPositiveOrientation = new List <Point>() { new Point(0, 0), new Point(1, 0), new Point(0, 1) }; //it's up to the user how to map 2D points to 3D, in this case we simply add a z-coordinate to the points: IEnumerable <Point3D> triangleInXYPlane = triangleInPositiveOrientation.Select(p => new Point3D(p.X, p.Y, 0)); foreach (Point3D point in triangleInXYPlane) { meshBuilder.Positions.Add(point); } Int32Collection indices = SweepLinePolygonTriangulator.Triangulate(triangleInPositiveOrientation); foreach (int index in indices) { meshBuilder.TriangleIndices.Add(index); } //Create a triangle with the reversed orientation, this should thus also be visible from the other side: List <Point> triangleInNegativeOrientation = new List <Point>() { new Point(0, 0), new Point(0, 1), new Point(1, 0) }; triangleInXYPlane = triangleInPositiveOrientation.Select(p => new Point3D(p.X, p.Y, 1)); foreach (Point3D point in triangleInXYPlane) { meshBuilder.Positions.Add(point); } indices = SweepLinePolygonTriangulator.Triangulate(triangleInNegativeOrientation); foreach (int index in indices) { //add 3 as we have already added a triangle before, making the starting index of this triangle 3 higher: meshBuilder.TriangleIndices.Add(index + 3); } }
/// <summary> /// Generate a simple Polygon and then triangulate it. /// The Result is then Displayed. /// </summary> /// <param name="sender">The Sender (i.e. the Button)</param> /// <param name="e">The routet Event Args</param> private void generatePolygonButton_Click(object sender, RoutedEventArgs e) { // Generate random Polygon var random = new Random(); var cnt = mViewModel.PointCount; mPolygonPoints = new List <Vector2>(); var angle = 0f; var angleDiff = 2f * (Single)Math.PI / cnt; var radius = 4f; // Random Radii for the Polygon var radii = new List <float>(); var innerRadii = new List <float>(); for (int i = 0; i < cnt; i++) { radii.Add(random.NextFloat(radius * 0.9f, radius * 1.1f)); innerRadii.Add(random.NextFloat(radius * 0.2f, radius * 0.3f)); } var hole1 = new List <Vector2>(); var hole2 = new List <Vector2>(); var holeDistance = 2f; var holeAngle = random.NextFloat(0, (float)Math.PI * 2); var cos = (float)Math.Cos(holeAngle); var sin = (float)Math.Sin(holeAngle); var offset1 = new Vector2(holeDistance * cos, holeDistance * sin); var offset2 = new Vector2(-holeDistance * cos, -holeDistance * sin); for (int i = 0; i < cnt; i++) { // Flatten a bit var radiusUse = radii[i]; mPolygonPoints.Add(new Vector2(radii[i] * (Single)Math.Cos(angle), radii[i] * (Single)Math.Sin(angle))); hole1.Add(offset1 + new Vector2(innerRadii[i] * (Single)Math.Cos(-angle), innerRadii[i] * (Single)Math.Sin(-angle))); hole2.Add(offset2 + new Vector2(innerRadii[i] * (Single)Math.Cos(-angle), innerRadii[i] * (Single)Math.Sin(-angle))); angle += angleDiff; } var holes = new List <List <Vector2> >() { hole1, hole2 }; // Triangulate and measure the Time needed for the Triangulation var before = DateTime.Now; var sLTI = SweepLinePolygonTriangulator.Triangulate(mPolygonPoints, holes); var after = DateTime.Now; // Generate the Output var geometry = new HelixToolkit.Wpf.SharpDX.MeshGeometry3D(); geometry.Positions = new HelixToolkit.Wpf.SharpDX.Core.Vector3Collection(); geometry.Normals = new HelixToolkit.Wpf.SharpDX.Core.Vector3Collection(); foreach (var point in mPolygonPoints.Union(holes.SelectMany(h => h))) { geometry.Positions.Add(new Vector3(point.X, 0, point.Y + 5)); geometry.Normals.Add(new Vector3(0, 1, 0)); } geometry.Indices = new HelixToolkit.Wpf.SharpDX.Core.IntCollection(sLTI); triangulatedPolygon.Geometry = geometry; var lb = new LineBuilder(); for (int i = 0; i < sLTI.Count; i += 3) { lb.AddLine(geometry.Positions[sLTI[i]], geometry.Positions[sLTI[i + 1]]); lb.AddLine(geometry.Positions[sLTI[i + 1]], geometry.Positions[sLTI[i + 2]]); lb.AddLine(geometry.Positions[sLTI[i + 2]], geometry.Positions[sLTI[i]]); } mViewModel.LineGeometry = lb.ToLineGeometry3D(); // Set the Lines if activated if (mViewModel.ShowTriangleLines) { lineTriangulatedPolygon.Geometry = mViewModel.LineGeometry; } else { lineTriangulatedPolygon.Geometry = null; } // Set the InfoLabel Text var timeNeeded = (after - before).TotalMilliseconds; infoLabel.Content = String.Format("Last triangulation of {0} Points took {1:0.##} Milliseconds!", triangulatedPolygon.Geometry.Positions.Count, timeNeeded); }
/// <summary> /// Triangulate the polygon by using the sweep line algorithm /// </summary> /// <returns>An index collection.</returns> public Int32Collection Triangulate() { return(SweepLinePolygonTriangulator.Triangulate(this.points)); }
/// <summary> /// Generate a simple Polygon and then triangulate it. /// The Result is then Displayed. /// </summary> /// <param name="sender">The Sender (i.e. the Button)</param> /// <param name="e">The routet Event Args</param> private void generatePolygonButton_Click(object sender, RoutedEventArgs e) { // Generate random Polygon var random = new Random(); var cnt = mViewModel.PointCount; mPolygonPoints = new List <Vector2>(); var angle = 0f; var angleDiff = 2f * (Single)Math.PI / cnt; var radius = 4f; // Random Radii for the Polygon var radii = new List <float>(); for (int i = 0; i < cnt; i++) { radii.Add(radius + random.NextFloat(-radius, radius)); } for (int i = 0; i < cnt; i++) { var last = i > 0 ? i - 1 : cnt - 1; var next = i < cnt - 1 ? i + 1 : 0; // Flatten a bit var radiusUse = radii[last] * 0.25f + radii[i] * 0.5f + radii[next] * 0.25f; mPolygonPoints.Add(new Vector2(radiusUse * (Single)Math.Cos(angle), radiusUse * (Single)Math.Sin(angle))); angle += angleDiff; } // Triangulate and measure the Time needed for the Triangulation var before = DateTime.Now; var sLTI = SweepLinePolygonTriangulator.Triangulate(mPolygonPoints); var after = DateTime.Now; // Generate the Output var geometry = new HelixToolkit.Wpf.SharpDX.MeshGeometry3D(); geometry.Positions = new HelixToolkit.Wpf.SharpDX.Core.Vector3Collection(); geometry.Normals = new HelixToolkit.Wpf.SharpDX.Core.Vector3Collection(); foreach (var point in mPolygonPoints) { geometry.Positions.Add(new Vector3(point.X, 0, point.Y + 5)); geometry.Normals.Add(new Vector3(0, 1, 0)); } geometry.Indices = new HelixToolkit.Wpf.SharpDX.Core.IntCollection(sLTI); triangulatedPolygon.Geometry = geometry; var lb = new LineBuilder(); for (int i = 0; i < sLTI.Count; i += 3) { lb.AddLine(geometry.Positions[sLTI[i]], geometry.Positions[sLTI[i + 1]]); lb.AddLine(geometry.Positions[sLTI[i + 1]], geometry.Positions[sLTI[i + 2]]); lb.AddLine(geometry.Positions[sLTI[i + 2]], geometry.Positions[sLTI[i]]); } mViewModel.LineGeometry = lb.ToLineGeometry3D(); // Set the Lines if activated if (mViewModel.ShowTriangleLines) { lineTriangulatedPolygon.Geometry = mViewModel.LineGeometry; } else { lineTriangulatedPolygon.Geometry = null; } // Set the InfoLabel Text var timeNeeded = (after - before).TotalMilliseconds; infoLabel.Content = String.Format("Last triangulation of {0} Points took {1:0.##} Milliseconds!", triangulatedPolygon.Geometry.Positions.Count, timeNeeded); }