//#endfor instanced to 'Vector2f' #endregion #region Public Members //#foreach instanced to 'Vector2d' /// <summary> /// Tesselates an outline using options to array of triangles. /// </summary> /// <param name="data">The input data. If options has OutlineEnd.NoEnd options, last and first element /// will be linked automatically (as with polygons). Otherwise, all points will be used.</param> /// <param name="options">The options of tesselation.</param> /// <param name="builder">The buolder that is used to build the mesh.</param> public static void Tesselate([NotNull] Vector2d[] data, [NotNull] TesselationOptionsd options, [NotNull] Storage.Builders.ITriangleBuilder2d builder) { if (data.Length < 2) { throw new ArgumentException("The data length must be at least 2, otherwise cannot tesselate."); } if (options.OutlineType == OutlineType.Line) { TesselateLine(data, options, builder); } else { throw new NotImplementedException("The feature not yet implemented."); } }
/// <summary> /// Tesselates outline as line (most common). /// </summary> /// <param name="points"></param> /// <param name="options"></param> /// <param name="mesh"></param> static void TesselateLine(Vector2d[] points, TesselationOptionsd options, Storage.Builders.ITriangleBuilder2d mesh) { // This is actually half width, because we go both ways. double width = options.LineThickness * (double)0.5; // Previous lower and upper coordinates, usually pen dependant. Vector2d grad = points[1] - points[0]; grad = new Vector2d(-grad.Y, grad.X).Normal; Vector2d prevLower = points[0] - grad * width, prevUpper = points[0] + grad * width; // We check if it is closed. bool isClosed = false; if (Vector2d.NearEqual(points[0], points[points.Length - 1])) { isClosed = true; // We correct prevLower and prevUpper. Vector2d p0, p1, p2; if (CalcPathIntersection(points[points.Length - 2], points[0], points[1], width, out p0, out p1, out p2)) { prevUpper = p0; prevLower = p2; } else { prevUpper = p2; prevLower = p0; } } else { if (options.OutlineEnd == OutlineEnd.NoEnd) { throw new ArgumentException("The outline must be 'linked' in order to have no end."); } } // We insert prevUpper and predLower. uint prevUpperId = mesh.AddControlPoints(prevUpper, prevLower); uint prevLowerId = prevUpperId + 1; // We go through all points. for (int i = 1; i < points.Length - 1; i++) { Vector2d p0, p1, p2; if (CalcPathIntersection(points[i - 1], points[i], points[i + 1], width, out p0, out p1, out p2)) { // We now add new values. uint p0Id = mesh.AddControlPoints(p0, p1, p2); uint p1Id = p0Id + 1; uint p2Id = p0Id + 2; // We now add triangles. mesh.AddIndexedTriangles(prevLowerId, p0Id, prevUpperId, prevLowerId, p1Id, p0Id, p0Id, p1Id, p2Id); prevLowerId = p2Id; prevUpperId = p0Id; } else { // We now add new values. uint p0Id = mesh.AddControlPoints(p0, p1, p2); uint p1Id = p0Id + 1; uint p2Id = p0Id + 2; mesh.AddIndexedTriangles(prevLowerId, p1Id, prevUpperId, prevLowerId, p0Id, p1Id, p0Id, p1Id, p2Id); prevLowerId = p0Id; prevUpperId = p2Id; } } if (isClosed) { // If it is closed, we must close it correctly. Vector2d p0, p1, p2; if (CalcPathIntersection(points[points.Length - 2], points[0], points[1], width, out p0, out p1, out p2)) { // We now add new values. uint p0Id = mesh.AddControlPoints(p0, p1, p2); uint p1Id = p0Id + 1; uint p2Id = p0Id + 2; // We now add triangles. mesh.AddIndexedTriangles(prevLowerId, p0Id, prevUpperId, prevLowerId, p1Id, p0Id, p0Id, p1Id, p2Id); } else { // We now add new values. uint p0Id = mesh.AddControlPoints(p0, p1, p2); uint p1Id = p0Id + 1; uint p2Id = p0Id + 2; mesh.AddIndexedTriangles(prevLowerId, p1Id, prevUpperId, prevLowerId, p0Id, p1Id, p0Id, p1Id, p2Id); } } else { // TODO: may need to implement other endings. if (options.OutlineEnd != OutlineEnd.Square) { throw new NotImplementedException("No other endings but 'Square' implemented."); } // Last point special again. Vector2d last = points[points.Length - 1]; grad = last - points[points.Length - 2]; grad = new Vector2d(-grad.Y, grad.X).Normal; Vector2d lower = last - grad * width; Vector2d upper = last + grad * width; // The lower id. uint lowerId = mesh.AddControlPoints(lower, upper); uint upperId = lowerId + 1; mesh.AddIndexedTriangles(prevLowerId, lowerId, upperId, prevLowerId, upperId, prevUpperId); } }