publicasyncTaskOpenTinDataset(){try{awaitArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(()=>{stringpath=@"d:\Data\Tin";varfileConnection=newFileSystemConnectionPath(newUri(path),FileSystemDatastoreType.Tin);using(FileSystemDatastoredataStore=newFileSystemDatastore(fileConnection)){// TIN is in a folder at d:\Data\Tin\TinDatasetstringdsName="TinDataset";using(vardataset=dataStore.OpenDataset<ArcGIS.Core.Data.Analyst3D.TinDataset>(dsName)){}}});}catch(GeodatabaseNotFoundOrOpenedExceptionexception){// Handle Exception.}}
Get a TIN Defintion
publicasyncTaskGetTinDatasetDefinition(){try{awaitArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(()=>{stringpath=@"d:\Data\Tin";varfileConnection=newFileSystemConnectionPath(newUri(path),FileSystemDatastoreType.Tin);using(FileSystemDatastoredataStore=newFileSystemDatastore(fileConnection)){// TIN is in a folder at d:\Data\Tin\TinDatasetstringdsName="TinDataset";using(vardef=dataStore.GetDefinition<ArcGIS.Core.Data.Analyst3D.TinDatasetDefinition>(dsName)){}}});}catch(GeodatabaseNotFoundOrOpenedExceptionexception){// Handle Exception.}}
// search all nodes that intersect the data extentusing(ArcGIS.Core.Data.Analyst3D.TinNodeCursornodeCursor=tinDataset.SearchNodes(null)){while(nodeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinNodenode=nodeCursor.Current){}}}// search within an extentArcGIS.Core.Data.Analyst3D.TinNodeFilternodeFilter=newArcGIS.Core.Data.Analyst3D.TinNodeFilter();nodeFilter.FilterEnvelope=envelope;using(ArcGIS.Core.Data.Analyst3D.TinNodeCursornodeCursor=tinDataset.SearchNodes(nodeFilter)){while(nodeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinNodenode=nodeCursor.Current){}}}// search all "inside" nodesnodeFilter=newArcGIS.Core.Data.Analyst3D.TinNodeFilter();nodeFilter.FilterType=ArcGIS.Core.Data.Analyst3D.TinFilterType.InsideDataArea;using(ArcGIS.Core.Data.Analyst3D.TinNodeCursornodeCursor=tinDataset.SearchNodes(nodeFilter)){while(nodeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinNodenode=nodeCursor.Current){}}}// search for super nodes onlynodeFilter=newArcGIS.Core.Data.Analyst3D.TinNodeFilter();nodeFilter.FilterEnvelope=tinDataset.GetSuperNodeExtent();nodeFilter.SuperNode=true;using(ArcGIS.Core.Data.Analyst3D.TinNodeCursornodeCursor=tinDataset.SearchNodes(nodeFilter)){while(nodeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinNodenode=nodeCursor.Current){}}}
Search for TIN Edges
// search all single edges that intersect the data extentusing(ArcGIS.Core.Data.Analyst3D.TinEdgeCursoredgeCursor=tinDataset.SearchEdges(null)){while(edgeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinEdgeedge=edgeCursor.Current){}}}// search within an extentArcGIS.Core.Data.Analyst3D.TinEdgeFilteredgeFilter=newArcGIS.Core.Data.Analyst3D.TinEdgeFilter();edgeFilter.FilterEnvelope=envelope;using(ArcGIS.Core.Data.Analyst3D.TinEdgeCursoredgeCursor=tinDataset.SearchEdges(edgeFilter)){while(edgeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinEdgeedge=edgeCursor.Current){}}}// search all "inside" edgesedgeFilter=newArcGIS.Core.Data.Analyst3D.TinEdgeFilter();edgeFilter.FilterType=ArcGIS.Core.Data.Analyst3D.TinFilterType.InsideDataArea;using(ArcGIS.Core.Data.Analyst3D.TinEdgeCursoredgeCursor=tinDataset.SearchEdges(edgeFilter)){while(edgeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinEdgeedge=edgeCursor.Current){}}}// search for hard edgesedgeFilter=newArcGIS.Core.Data.Analyst3D.TinEdgeFilter();edgeFilter.FilterByEdgeType=true;edgeFilter.EdgeType=ArcGIS.Core.Data.Analyst3D.TinEdgeType.HardEdge;using(ArcGIS.Core.Data.Analyst3D.TinEdgeCursoredgeCursor=tinDataset.SearchEdges(edgeFilter)){while(edgeCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinEdgeedge=edgeCursor.Current){}}}
Search for TIN Triangles
// search all triangles that intersect the data extentusing(ArcGIS.Core.Data.Analyst3D.TinTriangleCursortriangleCursor=tinDataset.SearchTriangles(null)){while(triangleCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinTriangletriangle=triangleCursor.Current){}}}// search within an extentArcGIS.Core.Data.Analyst3D.TinTriangleFiltertriangleFilter=newArcGIS.Core.Data.Analyst3D.TinTriangleFilter();triangleFilter.FilterEnvelope=envelope;using(ArcGIS.Core.Data.Analyst3D.TinTriangleCursortriangleCursor=tinDataset.SearchTriangles(triangleFilter)){while(triangleCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinTriangletriangle=triangleCursor.Current){}}}// search all "inside" trianglestriangleFilter=newArcGIS.Core.Data.Analyst3D.TinTriangleFilter();triangleFilter.FilterType=ArcGIS.Core.Data.Analyst3D.TinFilterType.InsideDataArea;using(ArcGIS.Core.Data.Analyst3D.TinTriangleCursortriangleCursor=tinDataset.SearchTriangles(triangleFilter)){while(triangleCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.TinTriangletriangle=triangleCursor.Current){}}}
Access TIN Elements by MapPoint
// "identify" the closest node, edge, triangleusing(varnearestNode=tinDataset.GetNearestNode(mapPoint)){}using(varnearestEdge=tinDataset.GetNearestEdge(mapPoint)){}using(vartriangle=tinDataset.GetTriangleByPoint(mapPoint)){}// get the set of natural neighbours // (set of nodes that "mapPoint" would connect with to form triangles if it was added to the TIN)IReadOnlyList<ArcGIS.Core.Data.Analyst3D.TinNode>naturalNeighbors=tinDataset.GetNaturalNeighbors(mapPoint);// get the set of triangles whose circumscribed circle contains "mapPoint" IReadOnlyList<ArcGIS.Core.Data.Analyst3D.TinTriangle>triangles=tinDataset.GetTriangleNeighborhood(mapPoint);
TIN Nodes
// node coordinatesvarcoord3D=node.Coordinate3D;varmapPoint=node.ToMapPoint();// is the node "inside"varisInsideNode=node.IsInsideDataArea;// get all other nodes connected to "node" IReadOnlyList<ArcGIS.Core.Data.Analyst3D.TinNode>adjNodes=node.GetAdjacentNodes();// get all edges that share "node" as a from node. IReadOnlyList<ArcGIS.Core.Data.Analyst3D.TinEdge>edges=node.GetIncidentEdges();// get all triangles that share "node"IReadOnlyList<ArcGIS.Core.Data.Analyst3D.TinTriangle>triangles=node.GetIncidentTriangles();
TIN Edges
// nodes of the edgevarnodes=edge.Nodes;// edge geometryvarpolyline=edge.ToPolyline();// edge lengthvarlength=edge.Length;// is the edge "inside"varisInsideEdge=edge.IsInsideDataArea;// edge type - regular/hard/softvaredgeType=edge.EdgeType;// get next (clockwise) edge in the trianglevarnextEdge=edge.GetNextEdgeInTriangle();// get previous (anti-clockwise) edge in the trianglevarprevEdge=edge.GetPreviousEdgeInTriangle();// get opposite edgevaroppEdge=edge.GetNeighbor();// get left trianglevarleftTriangle=edge.LeftTriangle;// get right trianglevarrightTriangle=edge.RightTriangle;
TIN Triangles
// nodes, edges of the trianglevartriNnodes=triangle.Nodes;vartriEdges=triangle.Edges;// triangle geometryvarpolygon=triangle.ToPolygon();// triangle lengthvartriLength=triangle.Length;// triangle area vartriArea=triangle.Area;// is the triangle "inside"varisInsideTriangle=triangle.IsInsideDataArea;// triangle aspect and slope (radians)varaspect=triangle.Aspect;varslope=triangle.Slope;// get centroidvarcentroid=triangle.GetCentroid();// get normalvarnormal=triangle.GetNormal();// get adjacent trianglesvaradjTriangles=triangle.GetAdjacentTriangles();// get area of triangle that falls between the z valuesdoubleminZ=1.0;doublemaxZ=3.0;IReadOnlyList<Coordinate3D>coords=triangle.GetPointsBetweenZs(minZ,maxZ);
varfields=featureClass.GetDefinition().GetFields();// Use the z-values from the geometries as the height fieldFieldheightField=fields.First(f =>f.FieldType==FieldType.Geometry);// Set the vertices from the geometries as TIN nodestinEditor=TinEditor.CreateFromFeatureClass(featureClass,null,heightField,null,TinSurfaceType.MassPoint);isInEditMode=tinEditor.IsInEditMode;// isInEditMode = true// Use the object ids as tag valuesFieldtagField=fields.First(f =>f.FieldType==FieldType.OID);// Set the lines from the geometries as TIN edgestinEditor=TinEditor.CreateFromFeatureClass(featureClass,null,heightField,tagField,TinSurfaceType.HardLine);isInEditMode=tinEditor.IsInEditMode;// isInEditMode = true// Only use certain geometries in the TINQueryFilterfilter=newQueryFilter(){ObjectIDs=newList<long>{2,6,7,8,9,10,14,17,21,22}};tinEditor=TinEditor.CreateFromFeatureClass(featureClass,filter,heightField,tagField,TinSurfaceType.HardLine);isInEditMode=tinEditor.IsInEditMode;// isInEditMode = true
Add geometries from feature class
varfields=featureClass.GetDefinition().GetFields();// Use the z-values from the geometries as the height fieldFieldheightField=fields.First(f =>f.FieldType==FieldType.Geometry);// Set the vertices from the geometries as TIN nodestinEditor.AddFromFeatureClass(featureClass,null,heightField,null,TinSurfaceType.MassPoint);// Use the object ids as tag valuesFieldtagField=fields.First(f =>f.FieldType==FieldType.OID);// Set the lines from the geometries as TIN edgestinEditor.AddFromFeatureClass(featureClass,null,heightField,tagField,TinSurfaceType.HardLine);// Only use certain geometries in the TINQueryFilterfilter=newQueryFilter(){ObjectIDs=newList<long>{2,6,7,8,9,10,14,17,21,22}};tinEditor.AddFromFeatureClass(featureClass,filter,heightField,tagField,TinSurfaceType.HardLine);
Add a geometry
// Add a point as a node with no tag value at height = 10. Points and multipoints can only be added as mass points.tinEditor.AddGeometry(point,TinSurfaceType.MassPoint,0,10);// Add a z-aware multipoint as a nodes with tag value = 12 at height equal to the z-values of the points. Points and multipoints can only be added as mass points.tinEditor.AddGeometryZ(multipointZ,TinSurfaceType.MassPoint,12);// Add a polyline as hard lines with tag value = 42 and height = 17.tinEditor.AddGeometry(polyline,TinSurfaceType.HardLine,42,17);// Add a z-aware polygon as an erase polygon with no tag value and height equal to the z-values of the vertices.tinEditor.AddGeometryZ(polygonZ,TinSurfaceType.HardErase,0);
Add mass points
// Add points with no tag value and height = 17.// The points have the same spatial reference as the tin editor, so there is no need to provide it. tinEditor.AddMassPoints(points,0,17);// Add coordinates as nodes with tag value = 42. The height will come from the z-values of the coordinates.tinEditor.AddMassPointsZ(coordinate3Ds,42);// Add z-aware points with tag value = 21. The height will come from the z-values of the points.// The points are in a different spatial reference than the tin editor, so we provide the spatial // reference of the points. The points will be projected to the spatial reference of the tin editor.tinEditor.AddMassPointsZ(pointsZ,21,SpatialReferenceBuilder.CreateSpatialReference(54004));
Add z-aware point
// Add a z-aware point with tag value = 56tinEditor.AddPointZ(pointZ,56);
Add polygons
// Add polygons with tagValue = 42 and height = 12. // The polygons are in a different spatial reference than the tin editor, so we provide the spatial // reference of the polygons. The polygons will be projected to the spatial reference of the tin editor.tinEditor.AddPolygons(polygons,TinSurfaceType.ZLessSoftLine,42,12,SpatialReferenceBuilder.CreateSpatialReference(54004));// Add z-aware polygons with no tag value. The height comes from the z-values of the vertices. // The polygons are in the same spatial reference as the tin editor, so there is no need to provide it.tinEditor.AddPolygonsZ(polygonsZ,TinSurfaceType.HardLine,0);
Add polylines
// Add polylines with tagValue = 42 and height = 12. // The polylines are in a different spatial reference than the tin editor, so we provide the spatial // reference of the polylines. The polylines will be projected to the spatial reference of the tin editor.tinEditor.AddPolylines(polylines,TinSurfaceType.ZLessSoftLine,42,12,SpatialReferenceBuilder.CreateSpatialReference(54004));// Add z-aware polylines with no tag value. The height comes from the z-values of the vertices. // The polylines are in the same spatial reference as the tin editor, so there is no need to provide it.tinEditor.AddPolylinesZ(polylinesZ,TinSurfaceType.HardLine,0);
Delete tag values
// Delete all edge tagstinEditor.DeleteEdgeTagValues();// Delete all node tagstinEditor.DeleteNodeTagValues();// Delete all triangle tagstinEditor.DeleteTriangleTagValues();
Set tag values
// Set the tag value for edge #6tinEditor.SetEdgeTagValue(6,42);// Set the tag value for node #8tinEditor.SetNodeTagValue(8,93);// Set the tag value for triangle #9tinEditor.SetTriangleTagValue(9,17);
Delete node
// Delete node by index tinEditor.DeleteNode(7);// Node indices start at 1.try{tinEditor.DeleteNode(0);}catch(ArgumentException){// Handle the exception}// Can't delete a super node (indices 1 - 4)try{tinEditor.DeleteNode(2);}catch(TinException){// Handle the exception}
Delete nodes outside of data area
// Delete all data nodes that are outside the data area. Does not delete super nodes.tinEditor.DeleteNodesOutsideDataArea();
Set edge type
// Set the type of edge #8tinEditor.SetEdgeType(8,TinEdgeType.SoftEdge);
Set z-value of a node
// Set the z-value of node #10tinEditor.SetNodeZ(10,12.5);
Set the spatial reference
// Set the spatial referencetinEditor.SetSpatialReference(SpatialReferenceBuilder.CreateSpatialReference(54004));
Set to constrained Delaunay
// Set the triangulation method to constrained Delaunay from this point forwardtinEditor.SetToConstrainedDelaunay();
Set triangle in/out of data area
// Set triangle #7 to be inside the data areatinEditor.SetTriangleInsideDataArea(7);// Set triangle #9 to be outside the data areatinEditor.SetTriangleInsideDataArea(9);
Create a new TIN and save edits
// Create a new TIN tinEditor=newTinEditor(envelope);tinEditor.AddMassPoints(points,42,13.7);// Since the TIN doesn't exist on disk, you can't call SaveEdits.// You must call SaveAs first.try{tinEditor.SaveEdits();}catch(TinException){// Handle the exception}// Since the TIN doesn't exist on disk, you can't call StopEditing(true).// You must call SaveAs first.try{tinEditor.StopEditing(true);}catch(TinException){// Handle the exception}// Now save the newly created TIN to disktinEditor.SaveAs("C:\\Tin1",false);// Delete a nodetinEditor.DeleteNode(7);// Since the TIN now exists on disk you can call SaveEditstinEditor.SaveEdits();// Delete another nodetinEditor.DeleteNode(11);// Since the TIN now exists on disk, you can call StopEditing(true).// The edits will be saved and the tin editor will be taken out of edit mode.tinEditor.StopEditing(true);boolisInEditMode=tinEditor.IsInEditMode;// isInEditMode = false// Now if you try to make an edit, an exception is thrown because the editor is not in edit mode.try{tinEditor.AddPointZ(pointZ,0);}catch(TinException){// Handle the exception}// Put the editor into edit mode.tinEditor.StartEditing();isInEditMode=tinEditor.IsInEditMode;// isInEditMode = true// Now you can add the pointtinEditor.AddPointZ(pointZ,0);// Oops, you didn't really want to add the point. You want to stop editing and discard the unsaved edits// since the last time the editor was put into edit mode. All previous saved edits remain.tinEditor.StopEditing(false);
Edit an existing TIN
// Create an instance of TinEditor from an existing TinDatasettinEditor=newTinEditor(tinDataset);intnumNodes=tinDataset.GetNodeCount();// numNodes = 10tinEditor.AddPointZ(pointZ,7);// Calling SaveEdits modifies the existing TINtinEditor.SaveEdits();numNodes=tinDataset.GetNodeCount();// numNodes = 11// Adding twenty pointstinEditor.AddMassPoints(points,10,112.5);// Calling SaveAs creates a new TIN on disk, and // the tin editor points to the new TIN.stringtinPath2="C:\\Tin2";tinEditor.SaveAs(tinPath2,true);tinEditor.StopEditing(true);TinDatasettinDataset2=OpenTin(tinPath2);// See https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-3D-Analyst-Data#working-with-tin-datanumNodes=tinDataset2.GetNodeCount();// numNodes = 31// The edits still show up in the original TIN while it is in memory, but if you open it// again you will see that it only has the edits that were saved before SaveAs was called.numNodes=tinDataset.GetNodeCount();// numNodes = 31tinDataset=OpenTin(tinPath);numNodes=tinDataset.GetNodeCount();// numNodes = 11
publicasyncTaskGetTerrainDefinition(){try{awaitArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(()=>{stringpath=@"d:\Data\Terrain\filegdb_Containing_A_Terrain.gdb";varfileConnection=newFileGeodatabaseConnectionPath(newUri(path));using(GeodatabasedataStore=newGeodatabase(fileConnection)){stringdsName="nameOfTerrain";using(varterrainDef=dataStore.GetDefinition<ArcGIS.Core.Data.Analyst3D.TerrainDefinition>(dsName)){// get the feature class names that are used in the terrainvarfcNames=terrainDef.GetFeatureClassNames();}}});}catch(GeodatabaseNotFoundOrOpenedExceptionexception){// Handle Exception.}}
publicasyncTaskOpenLasDataset(){try{awaitArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(()=>{stringpath=@"d:\Data\LASDataset";varfileConnection=newFileSystemConnectionPath(newUri(path),FileSystemDatastoreType.LasDataset);using(FileSystemDatastoredataStore=newFileSystemDatastore(fileConnection)){stringname="utrecht_tile.lasd";// can specify with or without the .lasd extensionusing(vardataset=dataStore.OpenDataset<ArcGIS.Core.Data.Analyst3D.LasDataset>(name)){}}});}catch(GeodatabaseNotFoundOrOpenedExceptionexception){// Handle Exception.}}
Get a LAS Dataset Defintion
publicasyncTaskGetLasDatasetDefinition(){try{awaitArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(()=>{stringpath=@"d:\Data\LASDataset";varfileConnection=newFileSystemConnectionPath(newUri(path),FileSystemDatastoreType.LasDataset);using(FileSystemDatastoredataStore=newFileSystemDatastore(fileConnection)){stringname="utrecht_tile.lasd";// can specify with or without the .lasd extensionusing(vardataset=dataStore.GetDefinition<ArcGIS.Core.Data.Analyst3D.LasDatasetDefinition>(name)){}}});}catch(GeodatabaseNotFoundOrOpenedExceptionexception){// Handle Exception.}}
Get Individual File Information from a LAS Dataset
// access by IDIReadOnlyList<ArcGIS.Core.Data.Analyst3D.LasPoint>pts=lasDataset.GetPointByID(123456);pts=lasDataset.GetPointByID(123456,envelope);ArcGIS.Core.Data.Analyst3D.LasPointpt=pts.FirstOrDefault();varcoords=pt.Coordinate3D;varmapPoint=pt.ToMapPoint();
Search LAS Points
// search all pointsusing(ArcGIS.Core.Data.Analyst3D.LasPointCursorptCursor=lasDataset.SearchPoints(null)){while(ptCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.LasPointpoint=ptCursor.Current){}}}// search within an extentArcGIS.Core.Data.Analyst3D.LasPointFilterpointFilter=newArcGIS.Core.Data.Analyst3D.LasPointFilter();pointFilter.FilterGeometry=envelope;using(ArcGIS.Core.Data.Analyst3D.LasPointCursorptCursor=lasDataset.SearchPoints(pointFilter)){while(ptCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.LasPointpoint=ptCursor.Current){}}}// search within an extent and limited to specific classification codespointFilter=newArcGIS.Core.Data.Analyst3D.LasPointFilter();pointFilter.FilterGeometry=envelope;pointFilter.ClassCodes=newList<int>{4,5};using(ArcGIS.Core.Data.Analyst3D.LasPointCursorptCursor=lasDataset.SearchPoints(pointFilter)){while(ptCursor.MoveNext()){using(ArcGIS.Core.Data.Analyst3D.LasPointpoint=ptCursor.Current){}}}
Search using pre initialized arrays
// search all pointsusing(ArcGIS.Core.Data.Analyst3D.LasPointCursorptCursor=lasDataset.SearchPoints(null)){intcount;Coordinate3D[]lasPointsRetrieved=newCoordinate3D[10000];while(ptCursor.MoveNextArray(lasPointsRetrieved,null,null,null,outcount)){varpoints=lasPointsRetrieved.ToList();// ...}}// search within an extent// use MoveNextArray retrieving coordinates, fileIndex and pointIdsArcGIS.Core.Data.Analyst3D.LasPointFilterfilter=newArcGIS.Core.Data.Analyst3D.LasPointFilter();filter.FilterGeometry=envelope;using(ArcGIS.Core.Data.Analyst3D.LasPointCursorptCursor=lasDataset.SearchPoints(filter)){intcount;Coordinate3D[]lasPointsRetrieved=newCoordinate3D[50000];int[]fileIndexes=newint[50000];double[]pointIds=newdouble[50000];while(ptCursor.MoveNextArray(lasPointsRetrieved,null,fileIndexes,pointIds,outcount)){varpoints=lasPointsRetrieved.ToList();}}