Skip to content
Product
Team
Enterprise
Explore
Marketplace
Pricing
Sign in
Sign up
Esri /
arcgis-pro-sdk-community-samples
Public
Code
Issues 2
Pull requests 1
Actions
Projects
Wiki
Security
Insights
arcgis-pro-sdk-community-samples/Map-Exploration/OverlayGroundSurface/Module1.cs /
@arcgisprosdk
arcgisprosdk ArcGIS Pro SDK 2.7 SDK for .NET
Latest commit 44183d0 on 16 Dec 2020
History
1 contributor
531 lines (474 sloc) 18.8 KB
/*
Copyright 2020 Esri
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Threading.Tasks;
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.Mapping;
namespace OverlayGroundSurface
{
/// <summary>
/// OverlayGroundSurface illustrates how to draw geometries over a ground surface using AddOverlay.
/// </summary>
/// <remarks>
/// 1. Download the Community Sample data (see under the 'Resources' section for downloading sample data). The sample data contains a folder called 'C:\Data\Configurations\Projects' with sample data required for this solution. Make sure that the Sample data (specifically CommunitySampleData-3D-mm-dd-yyyy.zip) is unzipped into c:\data and c:\data\PolyTest is available.
/// 1. This solution is using the **Newtonsoft.Json NuGet**. If needed, you can install the NuGet from the "NuGet Package Manager Console" by using this script: "Install-Package Newtonsoft.Json".
/// 1. In Visual Studio click the Build menu. Then select Build Solution.
/// 1. Click Start button to debug ArcGIS Pro.
/// 1. Open the Pro project file: PolyTest.aprx in the C:\Data\PolyTest\ folder. Open the 'Graphic Test' tab in ArcGIS Pro.
/// 
/// 1. Make sure that the 'Scene' is selected as the active map in ArcGIS Pro and then click on the 'Create 3D Polygon Tool'.
/// 1. Digitize a polygon on the map. Once a polygon has been digitized the buttons under the 'Polygon 2 Graphic' group are now enabled. These buttons can be used to 'slice' the digitized polygon into smaller parts.
/// 
/// 1. Note that the number of slices across the X axis can be controlled with the Resolution pull-down. The 'Elevation' pull-down can be used add an additional elevation offset to the Z axis when the polygon is rendered in a scene.
/// 1. Select: Resolution 4 and Elevation 5 on the respective pull-down and click the 'Make Ring MultiPatch' button.
/// 1. The Add-in now converts the digitized polygon into a multipatch geometry and renders the multipatch in 2D and 3D.
/// 
/// 1. Select: Resolution 50 and Elevation 20 on the respective pull-down and click the 'Make Ring MultiPatch' button.
/// 1. The Add-in now converts the digitized polygon into a higher resolution multipatch geometry and renders the multipatch in 3D and 3D.
/// 
/// </remarks>
internal class Module1 : Module
{
private static Module1 _this = null;
/// <summary>
/// Retrieve the singleton instance to this module here
/// </summary>
public static Module1 Current
{
get
{
return _this ?? (_this = (Module1)FrameworkApplication.FindModule("OverlayGroundSurface_Module"));
}
}
internal static MapView CurrentMapView { get; set; }
#region UI properties and states
private static List<Geometry> _geometries = new List<Geometry>();
private static bool _hasImportData = false;
internal static bool HasImportData
{
get { return _hasImportData; }
set { _hasImportData = value; }
}
internal static bool HasGeometries
{
get { return HasImportData && _geometries.Count > 0; }
}
internal static List<Geometry> Geometries
{
get
{
return _geometries;
}
set
{
if (value == null) _geometries = null;
else
{
_geometries.Clear();
if (value != null)
{
foreach (var geom in value)
{
_geometries.Add(geom.Clone());
}
}
}
SetState("has_geometry_state", _geometries != null && _geometries.Count > 0);
}
}
private static Polygon _polygon = null;
internal static Polygon Polygon
{
get
{
return _polygon;
}
set
{
if (value == null) _polygon = null;
else _polygon = value.Clone() as Polygon;
SetState("has_polygon_state", _polygon != null);
foreach (var mv in _graphics.Keys)
{
ClearGraphics(mv);
}
var mvs = new List<MapView>();
foreach (var mv in _graphic.Keys)
{
if (_graphic[mv] != null) mvs.Add(mv);
}
foreach (var mv in mvs)
{
_graphic[mv]?.Dispose();
_graphic[mv] = null;
}
HasImportData = false;
}
}
internal static void SetState(string stateName, bool active)
{
if (FrameworkApplication.State.Contains(stateName) == active) return;
// toggle the state
if (FrameworkApplication.State.Contains(stateName))
{
//deactivates the state
FrameworkApplication.State.Deactivate(stateName);
}
else
{
//activates the state
FrameworkApplication.State.Activate(stateName);
}
}
internal static double Resolution { get; set; } = 1.00;
internal static double Elevation { get; set; } = 1.00;
#endregion UI properties and states
#region Overlay Helpers
private static Dictionary<MapView, IDisposable> _graphic = new Dictionary<MapView, IDisposable>();
internal static void AddOrUpdateOverlay(Geometry geom, CIMSymbolReference symRef)
{
var mapView = Module1.CurrentMapView;
if (mapView == null) return;
ClearGraphics(mapView);
if (!_graphic.ContainsKey(mapView))
{
_graphic.Add(mapView, mapView.AddOverlay(geom, symRef));
return;
}
if (_graphic[mapView] == null)
{
if (geom is Multipatch)
{
var cimMpGraphic = new CIMMultiPatchGraphic
{
MultiPatch = geom as Multipatch,
Symbol = symRef,
Transparency = 64
};
_graphic[mapView] = mapView.AddOverlay(geom, symRef);
}
else
_graphic[mapView] = mapView.AddOverlay(geom, symRef);
}
else
mapView.UpdateOverlay(_graphic[mapView], geom, symRef);
}
internal static void ClearGraphic(MapView mapView)
{
if (mapView == null) return;
if (_graphic.ContainsKey(mapView))
{
_graphic[mapView]?.Dispose();
_graphic[mapView] = null;
}
}
private static Dictionary<MapView, List<IDisposable>> _graphics = new Dictionary<MapView, List<IDisposable>>();
private static void ClearGraphics(MapView mapView)
{
if (_graphics.ContainsKey(mapView))
{
foreach (var g in _graphics[mapView]) g.Dispose();
_graphics[mapView].Clear();
}
}
internal static void MultiAddOrUpdateOverlay(bool bFirst, Geometry geom, CIMSymbolReference symRef)
{
var mapView = Module1.CurrentMapView;
if (mapView == null) return;
if (bFirst)
{
ClearGraphic(mapView);
ClearGraphics(mapView);
}
if (!_graphics.ContainsKey(mapView))
{
_graphics.Add(mapView, new List<IDisposable>());
}
_graphics[mapView].Add(Module1.CurrentMapView?.AddOverlay(geom, symRef));
}
#endregion Overlay Helpers
#region Utility Helpers
internal static bool Is3D => (Module1.CurrentMapView?.ViewingMode == MapViewingMode.SceneGlobal || Module1.CurrentMapView?.ViewingMode == MapViewingMode.SceneLocal);
internal static double GetFishnetIntervalDistance(Envelope env)
{
return ((env.XMax - env.XMin) + (env.XMax - env.XMin) * 0.01) / Resolution;
}
#endregion Utility Helpers
#region Polygon Helpers
internal static List<Geometry> MakeFishnetPolygons(Polygon inputPoly)
{
List<Geometry> polygons = new List<Geometry>();
Envelope envPoly = inputPoly.Extent;
var interval = GetFishnetIntervalDistance(envPoly);
for (var dX = envPoly.XMin; dX < envPoly.XMax + interval; dX += interval)
{
for (var dY = envPoly.YMin; dY < envPoly.YMax + interval; dY += interval)
{
var cutEnv = EnvelopeBuilder.CreateEnvelope(dX, dY, dX + interval, dY + interval, envPoly.SpatialReference);
if (GeometryEngine.Instance.Intersects(cutEnv, inputPoly))
{
var addPolygonPart = GeometryEngine.Instance.Clip(inputPoly, cutEnv);
polygons.Add(addPolygonPart);
}
}
}
return polygons;
}
internal static Geometry MakeFishnetPolygon(Polygon inputPoly)
{
Envelope envPoly = inputPoly.Extent;
var interval = GetFishnetIntervalDistance(envPoly);
var pb = new PolygonBuilder(inputPoly.SpatialReference)
{
HasZ = true
};
for (var dX = envPoly.XMin; dX < envPoly.XMax + interval; dX += interval)
{
for (var dY = envPoly.YMin; dY < envPoly.YMax + interval; dY += interval)
{
var cutEnv = EnvelopeBuilder.CreateEnvelope(dX, dY, dX + interval, dY + interval, envPoly.SpatialReference);
if (GeometryEngine.Instance.Intersects(cutEnv, inputPoly))
{
var addPolygonPart = GeometryEngine.Instance.Clip(inputPoly, cutEnv) as Polygon;
if (addPolygonPart.Area < 0)
{
System.Diagnostics.Debug.WriteLine($@"area: {addPolygonPart.Area}");
}
pb.AddPart(addPolygonPart.Points);
}
}
}
return pb.ToGeometry();
}
#endregion Polygon Helpers
#region MultiPatch Helpers
internal static async Task<Geometry> MakeFishnetMultiPatchAsync(Polygon inputPoly)
{
Envelope envPoly = inputPoly.Extent;
var interval = GetFishnetIntervalDistance(envPoly);
var mColor = System.Windows.Media.Colors.LightCyan;
var materialRed = new BasicMaterial
{
Color = mColor,
EdgeColor = mColor,
EdgeWidth = 0
};
// create the multipatchBuilderEx object
var mpb = new MultipatchBuilderEx();
// create a list of patch objects
var patches = new List<Patch>();
for (var dX = envPoly.XMin; dX < envPoly.XMax + interval; dX += interval)
{
for (var dY = envPoly.YMin; dY < envPoly.YMax + interval; dY += interval)
{
var cutEnv = EnvelopeBuilder.CreateEnvelope(dX, dY, dX + interval, dY + interval,
envPoly.SpatialReference);
if (GeometryEngine.Instance.Intersects(cutEnv, inputPoly))
{
var addPolygonPart = GeometryEngine.Instance.Clip(inputPoly, cutEnv) as Polygon;
if (addPolygonPart.Area < 0)
{
System.Diagnostics.Debug.WriteLine($@"area: {addPolygonPart.Area}");
}
var result = await Module1.CurrentMapView.Map.GetZsFromSurfaceAsync(addPolygonPart);
if (result.Status == SurfaceZsResultStatus.Ok)
{
addPolygonPart = GeometryEngine.Instance.Move(result.Geometry, 0, 0, Module1.Elevation) as Polygon;
}
var patch = mpb.MakePatch(esriPatchType.TriangleStrip);
patch.Coords = GetPolygonAsTriangleStrip(addPolygonPart);
patch.Material = materialRed;
patches.Add(patch);
}
}
} // assign the patches to the multipatchBuilder
mpb.Patches = patches;
// call ToGeometry to get the multipatch
return mpb.ToGeometry();
}
internal static async Task<Multipatch> MakeFishnetRingMultiPatchAsync(Polygon inputPoly)
{
Envelope envPoly = inputPoly.Extent;
var interval = GetFishnetIntervalDistance(envPoly);
var mColor = System.Windows.Media.Colors.LightCyan;
var materialRed = new BasicMaterial
{
Color = mColor,
EdgeColor = mColor,
EdgeWidth = 0
};
// create the multipatchBuilderEx object
var mpb = new MultipatchBuilderEx();
// create a list of patch objects
var patches = new List<Patch>();
var first = true;
for (var dX = envPoly.XMin; dX < envPoly.XMax + interval; dX += interval)
{
for (var dY = envPoly.YMin; dY < envPoly.YMax + interval; dY += interval)
{
var cutEnv = EnvelopeBuilder.CreateEnvelope(dX, dY, dX + interval, dY + interval,
envPoly.SpatialReference);
if (GeometryEngine.Instance.Intersects(cutEnv, inputPoly))
{
var addPolygonPart = GeometryEngine.Instance.Clip(inputPoly, cutEnv) as Polygon;
if (addPolygonPart.Area < 0)
{
System.Diagnostics.Debug.WriteLine($@"area: {addPolygonPart.Area}");
}
var result = await Module1.CurrentMapView.Map.GetZsFromSurfaceAsync(addPolygonPart);
if (result.Status == SurfaceZsResultStatus.Ok)
{
addPolygonPart = GeometryEngine.Instance.Move(result.Geometry, 0, 0, Module1.Elevation) as Polygon;
}
var patch = mpb.MakePatch(first ? esriPatchType.FirstRing : esriPatchType.Ring);
first = false;
patch.InsertPoints(0, addPolygonPart.Points);
patch.Material = materialRed;
patches.Add(patch);
}
}
} // assign the patches to the multipatchBuilder
mpb.Patches = patches;
// call ToGeometry to get the multipatch
return mpb.ToGeometry() as Multipatch;
}
internal static List<Coordinate3D> GetPolygonAsTriangleStrip(Polygon poly)
{
if (poly.PointCount < 4)
{
throw new Exception($@"Polygon 2 Triangle failed, too few vertices: {poly.PointCount}");
}
int maxPoints = poly.PointCount - 1;
Coordinate3D[] coords = new Coordinate3D[maxPoints];
int iNext = 0;
foreach (var coord in poly.Copy3DCoordinatesToList())
{
if (iNext < maxPoints) coords[iNext++] = coord;
}
var lstCoords = new List<Coordinate3D>();
int iTop = maxPoints - 1;
int iBottom = 0;
lstCoords.Add(DebugCoord(iBottom, coords[iBottom++]));
lstCoords.Add(DebugCoord(iBottom, coords[iBottom++]));
lstCoords.Add(DebugCoord(iTop, coords[iTop--]));
var tick = true;
for (; iTop >= iBottom; tick = !tick)
{
lstCoords.Add(tick ? DebugCoord(iBottom, coords[iBottom++]) : DebugCoord(iTop, coords[iTop--]));
}
// get the coordinates in triangle strip order
return lstCoords;
}
internal static Coordinate3D DebugCoord(int idx, Coordinate3D coord)
{
// System.Diagnostics.Debug.WriteLine($@"Pnt: {idx} {coord.X} {coord.Y} {coord.Z} ");
return coord;
}
/// <summary>
/// Call from MCT.
/// </summary>
/// <returns></returns>
internal static CIMSymbolReference GetDefaultMeshSymbol()
{
// find a 3d symbol
var spi = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == "ArcGIS 3D");
if (spi == null) return null;
// create new structural features
var style_item = spi.SearchSymbols(StyleItemType.MeshSymbol, "").FirstOrDefault(si => si.Name.StartsWith("Gray 40%"));
var symbol = style_item?.Symbol as CIMMeshSymbol;
if (symbol == null) return null;
var meshSymbol = symbol.MakeSymbolReference();
return meshSymbol;
}
#endregion MultiPatch Helpers
#region Symbol Helpers
private static CIMSymbolReference _polySymbolRef = null;
internal static CIMSymbolReference GetPolygonSymbolRef()
{
if (_polySymbolRef != null) return _polySymbolRef;
//Creating a polygon with a red fill and blue outline.
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlueRGB, 2.0, SimpleLineStyle.Solid);
_polySymbolRef = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.CreateRGBColor(255, 190, 190),
SimpleFillStyle.Solid, outline).MakeSymbolReference();
return _polySymbolRef;
}
private static CIMSymbolReference _lineSymbolRef = null;
/// <summary>
/// Get a line symbol
/// Must be called from the MCT. Use QueuedTask.Run.
/// </summary>
/// <returns></returns>
internal static CIMSymbolReference GetLineSymbolRef()
{
if (_lineSymbolRef != null) return _lineSymbolRef;
_lineSymbolRef = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.RedRGB, 4,
SimpleLineStyle.Solid).MakeSymbolReference();
return _lineSymbolRef;
}
private static CIMSymbolReference _point3DSymbolRef = null;
private static CIMSymbolReference _point2DSymbolRef = null;
internal static CIMSymbolReference GetPointSymbolRef()
{
if (Is3D)
{
if (_point3DSymbolRef != null) return _point3DSymbolRef;
var pointSymbol = GetPointSymbol("ArcGIS 3D", @"Pushpin 2");
CIMPointSymbol pnt3DSym = pointSymbol.Symbol as CIMPointSymbol;
pnt3DSym.SetSize(200);
pnt3DSym.SetRealWorldUnits(true);
_point3DSymbolRef = pnt3DSym.MakeSymbolReference();
return _point3DSymbolRef;
}
if (_point2DSymbolRef != null) return _point2DSymbolRef;
CIMPointSymbol pntSym = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB, 8, SimpleMarkerStyle.Circle);
_point2DSymbolRef = pntSym.MakeSymbolReference();
return _point2DSymbolRef;
}
private static SymbolStyleItem GetPointSymbol(string styleProjectItemName, string symbolStyleName)
{
var style3DProjectItem = Project.Current.GetItems<StyleProjectItem>().Where(p => p.Name == styleProjectItemName).FirstOrDefault();
var symbolStyle = style3DProjectItem.SearchSymbols(StyleItemType.PointSymbol, symbolStyleName).FirstOrDefault();
return symbolStyle;
}
#endregion Symbol Helper
#region Overrides
/// <summary>
/// Called by Framework when ArcGIS Pro is closing
/// </summary>
/// <returns>False to prevent Pro from closing, otherwise True</returns>
protected override bool CanUnload()
{
//TODO - add your business logic
//return false to ~cancel~ Application close
return true;
}
#endregion Overrides
}
}
© 2022 GitHub, Inc.
Terms
Privacy
Security
Status
Docs
Contact GitHub
Pricing
API
Training
Blog
About
Loading complete