using ArcGIS.Core.CIM; using ArcGIS.Core.Data; using ArcGIS.Core.Geometry; using ArcGIS.Desktop.Catalog; using ArcGIS.Desktop.Core; using ArcGIS.Desktop.Editing; using ArcGIS.Desktop.Extensions; using ArcGIS.Desktop.Framework; using ArcGIS.Desktop.Framework.Contracts; using ArcGIS.Desktop.Framework.Dialogs; using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Layouts; using ArcGIS.Desktop.Mapping; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Test { internal class MultipatchSphere : Button { protected override void OnClick() { var mLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType().FirstOrDefault(l => l.ShapeType == esriGeometryType.esriGeometryMultiPatch); if (mLayer == null) return; var extent = MapView.Active.Extent; var centerPt = GeometryEngine.Instance.Centroid(extent); var size = 200; // The size of the shape in m (height, length, width).It must be greater than 0 var quality = 0.8; // A value between 0 and 1 inclusive. A higher quality number means more verticies for the shape resulting in a smoother shape. QueuedTask.Run(() => { // construct a point with Z var centerZ = MapPointBuilderEx.CreateMapPoint(centerPt.X, centerPt.Y, 500, centerPt.SpatialReference); var builder = new MultipatchBuilderEx(); MakeSpherePatches(builder, centerZ, size, quality); var multipatch = builder.ToGeometry(); // add to multipatch layer if (mLayer != null) { var op = new EditOperation(); op.Name = "Create mutlipatch"; op.Create(mLayer, multipatch); bool result = op.Execute(); } }); } // quality between 0 and 1 inclusive. // size > 0 private void MakeSpherePatches(MultipatchBuilderEx builder, MapPoint centerPt, double size, double quality) { int sMinLatResolution = 2, sMaxLatResolution = 18, sMinLonResolution = 1, sMaxLonResolution = 9; double radius = 0.5 * size; int latResolution = sMinLatResolution + System.Convert.ToInt32(quality * (sMaxLatResolution - sMinLatResolution)); int lonResolution = sMinLonResolution + System.Convert.ToInt32(quality * (sMaxLonResolution - sMinLonResolution)); double deltaLon = 0.5 * Math.PI / lonResolution; double deltaLat = Math.PI / latResolution; List parts = new List(); List vertices = new List(); List normals = new List(); Coordinate3D vertex = new Coordinate3D(); Coordinate3D normal = new Coordinate3D(); Coordinate3D northPole = new Coordinate3D(); Coordinate3D northPoleNormal = new Coordinate3D(); Coordinate3D southPole = new Coordinate3D(); Coordinate3D southPoleNormal = new Coordinate3D(); northPole.SetComponents(0.0, 0.0, radius); northPoleNormal.SetComponents(0.0, 0.0, 1.0); southPole.SetComponents(0.0, 0.0, -radius); southPoleNormal.SetComponents(0.0, 0.0, -1.0); double lonLeft = 2.0 * Math.PI + deltaLon; double lonRight, cosLeft, sinLeft, cosRight, sinRight, x, y, z; int i; for (i = 0; i < lonResolution; ++i) { lonRight = lonLeft - deltaLon; lonLeft = lonRight - deltaLon; cosLeft = Math.Cos(lonLeft); sinLeft = Math.Sin(lonLeft); cosRight = Math.Cos(lonRight); sinRight = Math.Sin(lonRight); vertices.Add(northPole); normals.Add(northPoleNormal); double lat = 0.5 * Math.PI - deltaLat, cosLat; int j; for (j = 1; j < latResolution; ++j, lat -= deltaLat) { cosLat = Math.Cos(lat); x = cosLat * cosRight; y = cosLat * sinRight; z = Math.Sin(lat); vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); x = cosLat * cosLeft; y = cosLat * sinLeft; vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); } lonRight = lonLeft - deltaLon; lonLeft = lonRight - deltaLon; cosLeft = Math.Cos(lonLeft); sinLeft = Math.Sin(lonLeft); cosRight = Math.Cos(lonRight); sinRight = Math.Sin(lonRight); vertices.Add(southPole); normals.Add(southPoleNormal); lat = deltaLat - 0.5 * Math.PI; for (j = 1; j < latResolution; ++j, lat += deltaLat) { cosLat = Math.Cos(lat); x = cosLat * cosRight; y = cosLat * sinRight; z = Math.Sin(lat); vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); x = cosLat * cosLeft; y = cosLat * sinLeft; vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); } if (i == lonResolution - 1) { vertices.Add(northPole); normals.Add(northPoleNormal); lat = 0.5 * Math.PI - deltaLat; cosLat = Math.Cos(lat); lonRight = lonLeft - deltaLon; x = cosLat * Math.Cos(lonRight); y = cosLat * Math.Sin(lonRight); z = Math.Sin(lat); vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); } } parts.Add(vertices.Count); lonLeft = 2.0 * Math.PI; for (i = 0; i < lonResolution; ++i) { lonRight = lonLeft - deltaLon; lonLeft = lonRight - deltaLon; cosLeft = Math.Cos(lonLeft); sinLeft = Math.Sin(lonLeft); cosRight = Math.Cos(lonRight); sinRight = Math.Sin(lonRight); vertices.Add(northPole); normals.Add(northPoleNormal); double lat = 0.5 * Math.PI - deltaLat, cosLat; int j; for (j = 1; j < latResolution; ++j, lat -= deltaLat) { cosLat = Math.Cos(lat); x = cosLat * cosRight; y = cosLat * sinRight; z = Math.Sin(lat); vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); x = cosLat * cosLeft; y = cosLat * sinLeft; vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); } parts.Add(vertices.Count); lonRight = lonLeft - deltaLon; lonLeft = lonRight - deltaLon; cosLeft = Math.Cos(lonLeft); sinLeft = Math.Sin(lonLeft); cosRight = Math.Cos(lonRight); sinRight = Math.Sin(lonRight); vertices.Add(southPole); normals.Add(southPoleNormal); lat = deltaLat - 0.5 * Math.PI; for (j = 1; j < latResolution; ++j, lat += deltaLat) { cosLat = Math.Cos(lat); x = cosLat * cosLeft; y = cosLat * sinLeft; z = Math.Sin(lat); vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); x = cosLat * cosRight; y = cosLat * sinRight; vertex.SetComponents(x * radius, y * radius, z * radius); normal.SetComponents(x, y, z); vertices.Add(vertex); normals.Add(normal); } parts.Add(vertices.Count); } var cVertices = vertices.Count; var cParts = parts.Count; // create a basic material var basicMaterial = new BasicMaterial(); basicMaterial.Color = System.Windows.Media.Color.FromRgb(255, 255, 255); basicMaterial.TransparencyPercent = 0; // create a list of patch objects var patches = new List(); // make each patch using the appropriate coordinates and add to the patch list int startVertex = 0; int endVertex = 0; for (int idx = 0; idx < cParts; idx++) { endVertex = (int)parts[idx]; if (idx > 0) startVertex = (int)parts[idx - 1]; int numVertices = endVertex - startVertex; // get the coordinates between startVertex and endVertex List tmpVertices = new List(); List tmpNormals = new List(); for (int jdx = startVertex; jdx < endVertex; jdx++) { tmpVertices.Add(new Coordinate3D(vertices[jdx])); tmpNormals.Add(new Coordinate3D(normals[jdx])); } // make the patch var patch = builder.MakePatch(esriPatchType.TriangleStrip); patch.Coords = MoveVertices(tmpVertices, centerPt); patch.Material = basicMaterial; patch.Normals = tmpNormals; // add to builder builder.Patches.Add(patch); } } private List MoveVertices(List vertices, MapPoint translate) { for (int idx = 0; idx < vertices.Count; idx++) { var v = vertices[idx]; v.X += translate.X; v.Y += translate.Y; v.Z += translate.Z; vertices[idx] = v; } return vertices; } } }