/// <summary> /// Get an Exist DataLakeGen2Item, return true is the item is a folder, return false if it's File /// </summary> /// <param name="container">the blob container</param> /// <param name="path">the path of the Items</param> /// <returns>return true if the item is a folder, else false</returns> public static bool GetExistDataLakeGen2Item(DataLakeFileSystemClient fileSystem, string path, out DataLakeFileClient fileClient, out DataLakeDirectoryClient dirClient) { try { if (string.IsNullOrEmpty(path)) { dirClient = fileSystem.GetDirectoryClient(""); fileClient = null; return(true); } fileClient = fileSystem.GetFileClient(path); PathProperties properties = fileClient.GetProperties().Value; if (isDirectory(properties)) { dirClient = fileSystem.GetDirectoryClient(path); fileClient = null; return(true); } else { dirClient = null; return(false); } } catch (RequestFailedException e) when(e.Status == 404) { // TODO: through exception that the item not exist throw new ArgumentException(string.Format("The Item in File System {0} on path {1} does not exist.", fileSystem.Name, path)); } }
private async Task <Blob> GetBlobAsync(string fullPath, CancellationToken cancellationToken) { DecomposePath(fullPath, out string fs, out string rp, false); if (StoragePath.IsRootPath(rp)) { try { ApiResponse <string> response = await _restApi.GetFilesystemProperties(fs); await response.EnsureSuccessStatusCodeAsync(); var fsProps = new PathProperties(response); return(LConvert.ToBlob(fs, fsProps)); } catch (ApiException ex) when(ex.StatusCode == HttpStatusCode.NotFound) { return(null); } } PathProperties pp; try { pp = await GetPathPropertiesAsync(fs, rp, "getProperties").ConfigureAwait(false); } catch (ApiException ex) when(ex.StatusCode == HttpStatusCode.NotFound) { return(null); } return(LConvert.ToBlob(fullPath, pp)); }
static void SkipRange( float distance, PathDistanceForwardIterator pathIt, PathPatternIterator patternIt, PathProperties pathProps, JoiningInfo[] joiningInfo, float[] segmentLengths) { float unitsRemaining = distance; while (unitsRemaining > Epsilon) { var result = pathIt.AdvanceBy(unitsRemaining, out unitsRemaining); switch (result) { case PathDistanceForwardIterator.Result.Ended: return; case PathDistanceForwardIterator.Result.Stepped: if (unitsRemaining < Epsilon) { return; } break; case PathDistanceForwardIterator.Result.NewSegment: HandleNewSegmentJoining(pathIt, patternIt, joiningInfo, pathProps.Stroke.HalfThickness, segmentLengths); break; } } }
private static string serviceUri = "FILL-IN-HERE"; // full account FQDN, not just the account name - it should look like https://{ACCOUNTNAME}.dfs.core.windows.net/ public static void Main(string[] args) { // Create Client Secret Credential var creds = new ClientSecretCredential(tenantId, applicationId, clientSecret); // Create data lake file service client object DataLakeServiceClient serviceClient = new DataLakeServiceClient(new Uri(serviceUri), creds); var name = "sample-filesystem" + Guid.NewGuid().ToString("n").Substring(0, 8); // Create data lake file system client object DataLakeFileSystemClient filesystemclient = serviceClient.GetFileSystemClient(name); filesystemclient.CreateIfNotExists(); try { long length; string fileName = "/Test/testFilename1.txt"; DataLakeFileClient file = filesystemclient.GetFileClient(fileName); // Upload a file - automatically creates any parent directories that don't exist length = BinaryData.FromString("This is test data to write.\r\nThis is the second line.\r\n").ToStream().Length; file.Upload(BinaryData.FromString("This is test data to write.\r\nThis is the second line.\r\n").ToStream(), true); file.Append(BinaryData.FromString("This is the added line.\r\n").ToStream(), length); file.Flush(length + BinaryData.FromString("This is the added line.\r\n").ToStream().Length); //Read file contents Response <FileDownloadInfo> fileContents = file.Read(); Console.WriteLine(BinaryData.FromStream(fileContents.Value.Content).ToString()); // Get the properties of the file PathProperties pathProperties = file.GetProperties(); PrintDirectoryEntry(pathProperties); // Rename a file string destFilePath = "/Test/testRenameDest3.txt"; file.Rename(destFilePath); file = filesystemclient.GetFileClient(destFilePath); Console.WriteLine("The file URI is " + file.Uri); // Enumerate directory foreach (var pathItem in filesystemclient.GetPaths("/Test")) { PrintDirectoryEntry(pathItem); } // Delete a directory and all it's subdirectories and files filesystemclient.DeleteDirectory("/Test"); } finally { filesystemclient.Delete(); } Console.WriteLine("Done. Press ENTER to continue ..."); Console.ReadLine(); }
public async Task AppendAsync() { // Create three temporary Lorem Ipsum files on disk that we can upload int contentLength = 10; string sampleFileContentPart1 = CreateTempFile(SampleFileContent.Substring(0, contentLength)); string sampleFileContentPart2 = CreateTempFile(SampleFileContent.Substring(contentLength, contentLength)); string sampleFileContentPart3 = CreateTempFile(SampleFileContent.Substring(contentLength * 2, contentLength)); // Make StorageSharedKeyCredential to pass to the serviceClient string storageAccountName = StorageAccountName; string storageAccountKey = StorageAccountKey; Uri serviceUri = StorageAccountBlobUri; StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey); // Get a reference to a FileSystemClient DataLakeServiceClient serviceClient = new DataLakeServiceClient(serviceUri, sharedKeyCredential); // Get a reference to a filesystem named "sample-filesystem-appendasync" and then create it DataLakeFileSystemClient filesystem = serviceClient.GetFileSystemClient(Randomize("sample-filesystem-append")); await filesystem.CreateAsync(); try { // Get a reference to a file named "sample-file" in a filesystem DataLakeFileClient file = filesystem.GetFileClient(Randomize("sample-file")); // Create the file await file.CreateAsync(); // Verify we created one file AsyncPageable <PathItem> response = filesystem.GetPathsAsync(); IList <PathItem> paths = await response.ToListAsync(); Assert.AreEqual(1, paths.Count); // Append data to an existing DataLake File. Append is currently limited to 4000 MB per call. // To upload a large file all at once, consider using UploadAsync() instead. await file.AppendAsync(File.OpenRead(sampleFileContentPart1), 0); await file.AppendAsync(File.OpenRead(sampleFileContentPart2), contentLength); await file.AppendAsync(File.OpenRead(sampleFileContentPart3), contentLength * 2); await file.FlushAsync(contentLength * 3); // Verify the contents of the file PathProperties properties = await file.GetPropertiesAsync(); Assert.AreEqual(contentLength * 3, properties.ContentLength); } finally { // Clean up after the test when we're finished await filesystem.DeleteAsync(); } }
/// <summary> /// decide if a object represent a folder of datalake gen2 /// </summary> /// <param name="fileProperties">the PathProperties of the datalakeGen2 Object</param> /// <returns>return true if it represent a folder of datalake gen2</returns> public static bool isDirectory(PathProperties fileProperties) { if (fileProperties.Metadata.Contains(new KeyValuePair <string, string>("hdi_isfolder", "true")) && fileProperties.ContentLength == 0) { return(true); } return(false); }
private static void PrintDirectoryEntry(PathProperties pathProperties) { Console.WriteLine($"ExpiresOn Time: {pathProperties.ExpiresOn}"); Console.WriteLine($"ContentType: {pathProperties.ContentType}"); Console.WriteLine($"Metadata: {pathProperties.Metadata}"); Console.WriteLine($"Created Time: {pathProperties.CreatedOn}"); Console.WriteLine($"Length: {pathProperties.ContentLength}"); Console.WriteLine($"Modified Time: {pathProperties.LastModified}"); Console.WriteLine(); }
/// <summary> /// Tesselate the shape into a mesh. /// </summary> protected override void GenerateMesh() { var seg1 = VectorUtils.MakePathLine( new Vector2(position.x, position.y + pointRadius), new Vector2(position.x, position.y - pointRadius) ); var seg2 = VectorUtils.MakePathLine( new Vector2(position.x + pointRadius, position.y), new Vector2(position.x - pointRadius, position.y) ); PathProperties pathProps = new PathProperties() { Stroke = new Stroke() { Color = colorOutline, HalfThickness = penSize / 2f / Screen.dpi } }; Path path1 = new Path() { Contour = new BezierContour() { Segments = seg1 }, PathProps = pathProps }; Path path2 = new Path() { Contour = new BezierContour() { Segments = seg2 }, PathProps = pathProps }; SceneNode markNode = new SceneNode() { Transform = Matrix2D.identity, Drawables = new List <IDrawable> { path1, path2 } }; tessellationScene.Root = markNode; shapeMesh = new Mesh(); var markGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions); VectorUtils.FillMesh(shapeMesh, markGeometry, 1.0f); }
public static DatalakePathProperties ConvertTo(this PathProperties subject) { subject.VerifyNotNull(nameof(subject)); return(new DatalakePathProperties { LastModified = subject.LastModified, ContentEncoding = subject.ContentEncoding, ETag = subject.ETag.ToString(), ContentType = subject.ContentType, ContentLength = subject.ContentLength, CreatedOn = subject.CreatedOn, }); }
public void Append() { // Create three temporary Lorem Ipsum files on disk that we can upload int contentLength = 10; string sampleFileContentPart1 = CreateTempFile(SampleFileContent.Substring(0, contentLength)); string sampleFileContentPart2 = CreateTempFile(SampleFileContent.Substring(contentLength, contentLength)); string sampleFileContentPart3 = CreateTempFile(SampleFileContent.Substring(contentLength * 2, contentLength)); // Make StorageSharedKeyCredential to pass to the serviceClient string storageAccountName = StorageAccountName; string storageAccountKey = StorageAccountKey; Uri serviceUri = StorageAccountBlobUri; StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey); // Create DataLakeServiceClient using StorageSharedKeyCredentials DataLakeServiceClient serviceClient = new DataLakeServiceClient(serviceUri, sharedKeyCredential); // Get a reference to a filesystem named "sample-filesystem-append" and then create it DataLakeFileSystemClient filesystem = serviceClient.GetFileSystemClient(Randomize("sample-filesystem-append")); filesystem.Create(); try { // Get a reference to a file named "sample-file" in a filesystem DataLakeFileClient file = filesystem.GetFileClient(Randomize("sample-file")); // Create the file file.Create(); // Verify we created one file Assert.AreEqual(1, filesystem.ListPaths().Count()); // Append data to the DataLake File file.Append(File.OpenRead(sampleFileContentPart1), 0); file.Append(File.OpenRead(sampleFileContentPart2), contentLength); file.Append(File.OpenRead(sampleFileContentPart3), contentLength * 2); file.Flush(contentLength * 3); // Verify the contents of the file PathProperties properties = file.GetProperties(); Assert.AreEqual(contentLength * 3, properties.ContentLength); } finally { // Clean up after the test when we're finished filesystem.Delete(); } }
public void Rename() { // Make StorageSharedKeyCredential to pass to the serviceClient string storageAccountName = StorageAccountName; string storageAccountKey = StorageAccountKey; Uri serviceUri = StorageAccountBlobUri; StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey); // Create DataLakeServiceClient using StorageSharedKeyCredentials DataLakeServiceClient serviceClient = new DataLakeServiceClient(serviceUri, sharedKeyCredential); // Get a reference to a filesystem named "sample-filesystem-rename" and then create it DataLakeFileSystemClient filesystem = serviceClient.GetFileSystemClient(Randomize("sample-filesystem-rename")); filesystem.Create(); try { // Create a DataLake Directory to rename it later DataLakeDirectoryClient directoryClient = filesystem.GetDirectoryClient(Randomize("sample-directory")); directoryClient.Create(); // Rename directory with new path/name and verify by making a service call (e.g. GetProperties) #region Snippet:SampleSnippetDataLakeFileClient_RenameDirectory DataLakeDirectoryClient renamedDirectoryClient = directoryClient.Rename("sample-directory2"); #endregion Snippet:SampleSnippetDataLakeFileClient_RenameDirectory PathProperties directoryPathProperties = renamedDirectoryClient.GetProperties(); // Delete the sample directory using the new path/name filesystem.DeleteDirectory("sample-directory2"); // Create a DataLake file. DataLakeFileClient fileClient = filesystem.GetFileClient(Randomize("sample-file")); fileClient.Create(); // Rename file with new path/name and verify by making a service call (e.g. GetProperties) #region Snippet:SampleSnippetDataLakeFileClient_RenameFile DataLakeFileClient renamedFileClient = fileClient.Rename("sample-file2"); #endregion Snippet:SampleSnippetDataLakeFileClient_RenameFile PathProperties filePathProperties = renamedFileClient.GetProperties(); // Delete the sample directory using the new path/name filesystem.DeleteFile("sample-file2"); } finally { // Clean up after the test when we're finished filesystem.Delete(); } }
public static Blob ToBlob(string fullPath, PathProperties pp) { var result = new Blob(fullPath) { Size = pp.Length, LastModificationTime = pp.LastModified }; if (pp.UserMetadata != null) { result.Metadata.MergeRange(pp.UserMetadata); } return(result); }
private static void TessellatePath(BezierContour contour, PathProperties pathProps, List <VectorUtils.Geometry> geoms, VectorUtils.TessellationOptions options) { if (pathProps.Stroke != null) { Vector2[] vertices; UInt16[] indices; VectorUtils.TessellatePath(contour, pathProps, options, out vertices, out indices); var color = pathProps.Stroke.Color; geoms.Add(new VectorUtils.Geometry() { Vertices = vertices, Indices = indices, Color = color }); } }
public static DatalakePathProperties ConvertTo(this PathProperties subject, string path) { subject.VerifyNotNull(nameof(subject)); path.VerifyNotEmpty(nameof(path)); return(new DatalakePathProperties { Path = path, LastModified = subject.LastModified, ContentEncoding = subject.ContentEncoding, ETag = subject.ETag, ContentType = subject.ContentType, ContentLength = subject.ContentLength, CreatedOn = subject.CreatedOn, }); }
public void Upload() { // Create three temporary Lorem Ipsum files on disk that we can upload int contentLength = 10; string sampleFileContent = CreateTempFile(SampleFileContent.Substring(0, contentLength)); // Make StorageSharedKeyCredential to pass to the serviceClient string storageAccountName = StorageAccountName; string storageAccountKey = StorageAccountKey; Uri serviceUri = StorageAccountBlobUri; StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey); // Create DataLakeServiceClient using StorageSharedKeyCredentials DataLakeServiceClient serviceClient = new DataLakeServiceClient(serviceUri, sharedKeyCredential); // Get a reference to a filesystem named "sample-filesystem-append" and then create it DataLakeFileSystemClient filesystem = serviceClient.GetFileSystemClient(Randomize("sample-filesystem-append")); filesystem.Create(); try { // Get a reference to a file named "sample-file" in a filesystem DataLakeFileClient file = filesystem.GetFileClient(Randomize("sample-file")); // Create the file file.Create(); // Verify we created one file Assert.AreEqual(1, filesystem.GetPaths().Count()); // Upload content to the file. When using the Upload API, you don't need to create the file first. // If the file already exists, it will be overwritten. // For larger files, Upload() will upload the file in multiple sequential requests. file.Upload(File.OpenRead(sampleFileContent), true); // Verify the contents of the file PathProperties properties = file.GetProperties(); Assert.AreEqual(contentLength, properties.ContentLength); } finally { // Clean up after the test when we're finished filesystem.Delete(); } }
public static Blob ToBlob(string fullPath, PathProperties path) { var blob = new Blob(fullPath) { Size = path.Length, LastModificationTime = path.LastModified }; blob.TryAddProperties( "ETag", path.ETag, "ContentType", path.ContentType, "ResourceType", path.ResourceType); if (path.UserMetadata != null) { blob.Metadata.MergeRange(path.UserMetadata); } return(blob); }
public void GetProperties() { // Make StorageSharedKeyCredential to pass to the serviceClient string storageAccountName = StorageAccountName; string storageAccountKey = StorageAccountKey; Uri serviceUri = StorageAccountBlobUri; StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey); // Create DataLakeServiceClient using StorageSharedKeyCredentials DataLakeServiceClient serviceClient = new DataLakeServiceClient(serviceUri, sharedKeyCredential); // Get a reference to a filesystem named "sample-filesystem-rename" and then create it DataLakeFileSystemClient filesystem = serviceClient.GetFileSystemClient(Randomize("sample-filesystem")); filesystem.Create(); try { // Create a DataLake Directory to rename it later DataLakeDirectoryClient directoryClient = filesystem.GetDirectoryClient(Randomize("sample-directory")); directoryClient.Create(); #region Snippet:SampleSnippetDataLakeDirectoryClient_GetProperties // Get Properties on a Directory PathProperties directoryPathProperties = directoryClient.GetProperties(); #endregion Snippet:SampleSnippetDataLakeDirectoryClient_GetProperties // Create a DataLake file DataLakeFileClient fileClient = filesystem.GetFileClient(Randomize("sample-file")); fileClient.Create(); #region Snippet:SampleSnippetDataLakeFileClient_GetProperties // Get Properties on a File PathProperties filePathProperties = fileClient.GetProperties(); #endregion Snippet:SampleSnippetDataLakeFileClient_GetProperties } finally { // Clean up after the test when we're finished filesystem.Delete(); } }
public void Append_Simple() { // Create Sample File to read content from string sampleFilePath = CreateTempFile(SampleFileContent); // Make StorageSharedKeyCredential to pass to the serviceClient string storageAccountName = StorageAccountName; string storageAccountKey = StorageAccountKey; Uri serviceUri = StorageAccountBlobUri; StorageSharedKeyCredential sharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, storageAccountKey); // Create DataLakeServiceClient using StorageSharedKeyCredentials DataLakeServiceClient serviceClient = new DataLakeServiceClient(serviceUri, sharedKeyCredential); // Get a reference to a filesystem named "sample-filesystem-append" and then create it DataLakeFileSystemClient filesystem = serviceClient.GetFileSystemClient(Randomize("sample-filesystem-append")); filesystem.Create(); try { #region Snippet:SampleSnippetDataLakeFileClient_Append // Create a file DataLakeFileClient file = filesystem.GetFileClient(Randomize("sample-file")); file.Create(); // Append data to the DataLake File file.Append(File.OpenRead(sampleFilePath), 0); file.Flush(SampleFileContent.Length); #endregion Snippet:SampleSnippetDataLakeFileClient_Append // Verify the contents of the file PathProperties properties = file.GetProperties(); Assert.AreEqual(SampleFileContent.Length, properties.ContentLength); } finally { // Clean up after the test when we're finished filesystem.Delete(); } }
/// <summary> /// Tessellate the shape into geometry data. /// </summary> protected override void GenerateGeometry() { if ((shapeGeometry != null) && (!shapeDirty)) { return; } PathProperties pathProps = new PathProperties() { Stroke = new Stroke() { Color = colorOutline, HalfThickness = penSize / 2f * penToMeshScale } }; Shape textShape = new Shape() { Contours = new BezierContour[] { }, PathProps = pathProps }; shapeNode = new SceneNode() { Transform = matrixTransform, Shapes = new List <Shape> { textShape } }; tessellationScene.Root = shapeNode; shapeGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions); shapeDirty = false; }
private static void TessellatePath(BezierContour contour, PathProperties pathProps, List <Geometry> geoms, TessellationOptions tessellationOptions) { UnityEngine.Profiling.Profiler.BeginSample("TessellatePath"); if (pathProps.Stroke != null) { Vector2[] vertices; UInt16[] indices; Vector2[][] paths; ShapeUtils.TessellatePath(contour, pathProps, tessellationOptions, out vertices, out indices, out paths); var color = pathProps.Stroke.Color; if (indices.Length > 0) { geoms.Add(new Geometry() { Vertices = vertices, Indices = indices, Paths = paths, Color = color }); } } UnityEngine.Profiling.Profiler.EndSample(); }
public MovinShape(MovinLayer layer, BodymovinShape content) { this.content = content; if (content.paths == null || content.paths.Length < 1) { Debug.Log("DON'T DRAW SHAPE -> NO PTS"); return; } this.layer = layer; this.movin = layer.movin; Transform parent = layer.transform; /* FIRST SHAPE PROPS */ points = (BodyPoint[])content.paths[0].points.Clone(); motionSet = content.paths[0].animSets; closed = content.paths[0].closed; /* ANIM SETUP */ MotionSetup(ref animated, ref motion, motionSet); MotionSetup(ref strokeColorAnimated, ref mstrokec, content.strokeColorSets); MotionSetup(ref fillColorAnimated, ref mfillc, content.fillColorSets); /* GAMEOBJECT, MESH, MATERIAL */ gameObject = new GameObject(content.item.ty + " pts: " + points.Length + " closed: " + closed); transform.SetParent(parent, false); transform.localPosition = -layer.content.anchorPoint; mesh = new Mesh(); filter = gameObject.AddComponent <MeshFilter>(); filter.mesh = mesh; renderer = gameObject.AddComponent <MeshRenderer>(); renderer.material = new Material(Shader.Find("Sprites/Default")); //renderer.material = new Material(Shader.Find("Unlit/Vector")); sorting = gameObject.AddComponent <SortingGroup>(); sorting.sortingOrder = movin.sort + layer.sort; /* SETUP VECTOR */ Color stClr = (content.strokeColor == null) ? new Color(1, 1, 1) : new Color(content.strokeColor[0], content.strokeColor[1], content.strokeColor[2]); Color flClr = (content.fillColor == null) ? new Color(1, 1, 1) : new Color(content.fillColor[0], content.fillColor[1], content.fillColor[2]); currentStrokeColor = new Vector3(stClr.r, stClr.g, stClr.b); currentFillColor = new Vector3(flClr.r, flClr.g, flClr.b); fill = content.fillHidden || content.fillColor == null ? null : new SolidFill() { Color = flClr }; stroke = content.strokeHidden || content.strokeColor == null ? null : new Stroke() { Color = stClr, HalfThickness = content.strokeWidth * movin.strokeWidth }; props = new PathProperties() { Stroke = stroke }; shape = new Shape() { Fill = fill, PathProps = props, FillTransform = Matrix2D.identity }; options = movin.options; scene = new Scene() { Root = new SceneNode() { Shapes = new List <Shape> { shape } } }; UpdateMesh(); // ADDITIONAL SHAPE PATHS slaves = new MovinShapeSlave[content.paths.Length - 1]; for (int i = 1; i <= slaves.Length; i++) { slaves[i - 1] = new MovinShapeSlave(this, content.paths[i], movin.strokeWidth); } }
public MovinShapeSlave(MovinShape master, BodymovinShapePath path, float strokeWidth = 1f) { this.master = master; this.path = path; Transform parent = master.transform.parent; /* SHAPE PROPS */ points = (BodyPoint[])path.points.Clone(); motionSet = path.animSets; closed = path.closed; /* ANIM SETUP */ MotionSetup(ref animated, ref motion, motionSet); /* GAMEOBJECT */ gameObject = new GameObject(master.content.item.ty + " pts: " + points.Length + " closed: " + closed); transform.SetParent(parent, false); transform.localPosition = master.transform.localPosition; mesh = new Mesh(); filter = gameObject.AddComponent <MeshFilter>(); filter.mesh = mesh; renderer = gameObject.AddComponent <MeshRenderer>(); renderer.material = master.renderer.material; sorting = gameObject.AddComponent <UnityEngine.Rendering.SortingGroup>(); sorting.sortingOrder = master.sorting.sortingOrder; /* SETUP VECTOR */ fill = master.content.fillHidden || master.content.fillColor == null ? null : new SolidFill() { Color = master.fill.Color }; stroke = master.content.strokeHidden || master.content.strokeColor == null ? null : new Stroke() { Color = master.stroke.Color, HalfThickness = master.content.strokeWidth * strokeWidth }; props = new PathProperties() { Stroke = stroke }; shape = new Shape() { Fill = fill, PathProps = props, FillTransform = Matrix2D.identity }; options = master.options; scene = new Scene() { Root = new SceneNode() { Shapes = new List <Shape> { shape } } }; UpdateMesh(); }
/// <summary> /// Tessellate the shape into geometry data. /// </summary> protected override void GenerateGeometry() { if ((shapeGeometry != null) && (!shapeDirty)) { return; } var seg1 = VectorUtils.MakePathLine( new Vector2(position.x, position.y + pointRadius), new Vector2(position.x, position.y - pointRadius) ); var seg2 = VectorUtils.MakePathLine( new Vector2(position.x + pointRadius, position.y), new Vector2(position.x - pointRadius, position.y) ); PathProperties pathProps = new PathProperties() { Stroke = new Stroke() { Color = colorOutline, HalfThickness = penSize / 2f / Screen.dpi } }; Shape segment1 = new Shape() { Contours = new BezierContour[] { new BezierContour { Segments = seg1 } }, PathProps = pathProps }; Shape segment2 = new Shape() { Contours = new BezierContour[] { new BezierContour { Segments = seg2 } }, PathProps = pathProps }; Shape circle = new Shape(); VectorUtils.MakeCircleShape(circle, position, pointRadius); circle.PathProps = pathProps; shapeNode = new SceneNode() { Transform = matrixTransform, Shapes = new List <Shape> { segment1, segment2, circle } }; tessellationScene.Root = shapeNode; shapeGeometry = VectorUtils.TessellateScene(tessellationScene, tessellationOptions); shapeDirty = false; }
/// <summary> /// Tessellates a path. /// </summary> /// <param name="contour">The path to tessellate</param> /// <param name="pathProps">The path properties</param> /// <param name="tessellateOptions">The tessellation options</param> /// <param name="vertices">The resulting vertices</param> /// <param name="indices">The resulting triangles</param> /// <remarks> /// The individual line segments generated during tessellation are made out of a set of ordered vertices. It is important /// to honor this ordering so joining and and capping connect properly with the existing vertices without generating dupes. /// The ordering assumed is as follows: /// The last two vertices of a piece must be such that the first is generated at the end with a positive half-thickness /// while the second vertex is at the end too but at a negative half-thickness. /// No assumptions are enforced for other vertices before the two last vertices. /// </remarks> public static void TessellatePath(BezierContour contour, PathProperties pathProps, TessellationOptions tessellateOptions, out Vector2[] vertices, out UInt16[] indices, out Vector2[][] paths) { if (tessellateOptions.StepDistance < Epsilon) { throw new Exception("stepDistance too small"); } if (contour.Segments.Length < 2) { vertices = new Vector2[0]; indices = new UInt16[0]; paths = new Vector2[0][]; return; } UnityEngine.Profiling.Profiler.BeginSample("TessellatePath"); float[] segmentLengths = ShapeUtils.SegmentsLengths(contour.Segments, contour.Closed); // Approximate the number of vertices/indices we need to store the results so we reduce memory reallocations during work float approxTotalLength = 0.0f; foreach (var s in segmentLengths) { approxTotalLength += s; } int approxStepCount = Math.Max((int)(approxTotalLength / tessellateOptions.StepDistance + 0.5f), 2); if (pathProps.Stroke.Pattern != null) { approxStepCount += pathProps.Stroke.Pattern.Length * 2; } List <Vector2> verts = new List <Vector2>(approxStepCount * 2 + 32); // A little bit possibly for the endings List <UInt16> inds = new List <UInt16>((int)(verts.Capacity * 1.5f)); // Usually every 4 verts represent a quad that uses 6 indices List <Vector2[]> pats = new List <Vector2[]>(); var patternIt = new PathPatternIterator(pathProps.Stroke.Pattern, pathProps.Stroke.PatternOffset); var pathIt = new PathDistanceForwardIterator(contour.Segments, contour.Closed, tessellateOptions.MaxCordDeviationSquared, tessellateOptions.MaxTanAngleDeviationCosine, tessellateOptions.SamplingStepSize); JoiningInfo[] joiningInfo = new JoiningInfo[2]; HandleNewSegmentJoining(pathIt, patternIt, joiningInfo, pathProps.Stroke.HalfThickness, segmentLengths); int rangeIndex = 0; while (!pathIt.Ended) { if (patternIt.IsSolid) { TessellateRange(patternIt.SegmentLength, pathIt, patternIt, pathProps, tessellateOptions, joiningInfo, segmentLengths, approxTotalLength, rangeIndex++, verts, inds, pats); } else { SkipRange(patternIt.SegmentLength, pathIt, patternIt, pathProps, joiningInfo, segmentLengths); } patternIt.Advance(); } vertices = verts.ToArray(); indices = inds.ToArray(); paths = pats.ToArray(); UnityEngine.Profiling.Profiler.EndSample(); }
static void TessellateRange( float distance, PathDistanceForwardIterator pathIt, PathPatternIterator patternIt, PathProperties pathProps, TessellationOptions tessellateOptions, JoiningInfo[] joiningInfo, float[] segmentLengths, float totalLength, int rangeIndex, List <Vector2> verts, List <UInt16> inds, List <Vector2[]> pats) { bool startOfLoop = pathIt.Closed && (pathIt.CurrentSegment == 0) && (pathIt.CurrentT == 0.0f); if (startOfLoop && (joiningInfo[0] != null)) { GenerateJoining(joiningInfo[0], pathProps.Corners, pathProps.Stroke.HalfThickness, pathProps.Stroke.TippedCornerLimit, tessellateOptions, verts, inds); } else { var pathEnding = pathProps.Head; // If pattern at the end will overlap with beginning, use a chopped ending to allow merging if (pathIt.Closed && rangeIndex == 0 && patternIt.IsSolidAt(pathIt.CurrentT) && patternIt.IsSolidAt(totalLength)) { pathEnding = PathEnding.Chop; } GenerateTip(ShapeUtils.PathSegmentAtIndex(pathIt.Segments, pathIt.CurrentSegment), true, pathIt.CurrentT, pathEnding, pathProps.Stroke.HalfThickness, tessellateOptions, verts, inds); } float startingLength = pathIt.LengthSoFar; float unitsRemaining = Mathf.Min(tessellateOptions.StepDistance, distance); bool endedEntirePath = false; for (;;) { var result = pathIt.AdvanceBy(unitsRemaining, out unitsRemaining); if (result == PathDistanceForwardIterator.Result.Ended) { endedEntirePath = true; break; } else if (result == PathDistanceForwardIterator.Result.NewSegment) { if (joiningInfo[1] != null) { GenerateJoining(joiningInfo[1], pathProps.Corners, pathProps.Stroke.HalfThickness, pathProps.Stroke.TippedCornerLimit, tessellateOptions, verts, inds); } else { AddSegment(ShapeUtils.PathSegmentAtIndex(pathIt.Segments, pathIt.CurrentSegment), pathIt.CurrentT, pathProps.Stroke.HalfThickness, null, pathIt.SegmentLengthSoFar, verts, inds); } HandleNewSegmentJoining(pathIt, patternIt, joiningInfo, pathProps.Stroke.HalfThickness, segmentLengths); } if ((unitsRemaining <= Epsilon) && !TryGetMoreRemainingUnits(ref unitsRemaining, pathIt, startingLength, distance, tessellateOptions.StepDistance)) { break; } if (result == PathDistanceForwardIterator.Result.Stepped) { AddSegment(ShapeUtils.PathSegmentAtIndex(pathIt.Segments, pathIt.CurrentSegment), pathIt.CurrentT, pathProps.Stroke.HalfThickness, joiningInfo, pathIt.SegmentLengthSoFar, verts, inds); } } // Ending if (endedEntirePath && pathIt.Closed) { // No joining needed, the start and end of the path should just connect inds.Add(0); inds.Add(1); inds.Add((UInt16)(verts.Count - 2)); inds.Add((UInt16)(verts.Count - 1)); inds.Add((UInt16)(verts.Count - 2)); inds.Add(1); } else { AddSegment(ShapeUtils.PathSegmentAtIndex(pathIt.Segments, pathIt.CurrentSegment), pathIt.CurrentT, pathProps.Stroke.HalfThickness, joiningInfo, pathIt.SegmentLengthSoFar, verts, inds); GenerateTip(ShapeUtils.PathSegmentAtIndex(pathIt.Segments, pathIt.CurrentSegment), false, pathIt.CurrentT, pathProps.Tail, pathProps.Stroke.HalfThickness, tessellateOptions, verts, inds); } }