protected override void OnClick() { QueuedTask.Run(async() => { //get sketch geometry var sketchGeom = await MapView.Active.GetCurrentSketchAsync(); //return if the sketch doesn't have enough points for its geometry type if ((sketchGeom.GeometryType == GeometryType.Polygon && sketchGeom.PointCount < 3) || (sketchGeom.GeometryType == GeometryType.Polyline && sketchGeom.PointCount < 2)) { return; } //get the sketch as a point collection var pointCol = ((Multipart)sketchGeom).Points; //get the last point in the sketch based on its geometry type var lastSketchPoint = pointCol[(sketchGeom.GeometryType == GeometryType.Polygon) ? pointCol.Count - 2 : pointCol.Count - 1]; //build a geometry with the last sketch point and set the sketch if (sketchGeom.GeometryType == GeometryType.Polygon) { //sketch polygons need two points for the initial feedback to work var sketchPoly = new PolygonBuilderEx(new[] { lastSketchPoint, lastSketchPoint }, AttributeFlags.None); await MapView.Active.SetCurrentSketchAsync(sketchPoly.ToGeometry()); } else { var sketchPolyline = new PolylineBuilderEx(new[] { lastSketchPoint }, AttributeFlags.None); await MapView.Active.SetCurrentSketchAsync(sketchPolyline.ToGeometry()); } }); }
private static Geometry GetGeometryFromBuffer(byte[] geomBuffer, SpatialReference sr) { var geomType = GetGeometryType(geomBuffer); switch (geomType) { case GeometryType.Point: { int offset = 4; double x = DoubleWithNaN(BitConverter.ToDouble(geomBuffer, offset)); offset += 8; double y = DoubleWithNaN(BitConverter.ToDouble(geomBuffer, offset)); var mp = MapPointBuilderEx.FromEsriShape(geomBuffer, sr); //System.Diagnostics.Debug.WriteLine($@"x: {x} = {mp.X} y: {y} = {mp.Y}"); return(mp); } case GeometryType.Polyline: { var line = PolylineBuilderEx.FromEsriShape(geomBuffer, sr); return(line); } case GeometryType.Polygon: { var poly = PolygonBuilderEx.FromEsriShape(geomBuffer, sr); return(poly); } } return(null); }
/// <summary> /// Create sample polyline feature using the geometries from the point feature layer. /// </summary> /// <param name="polylineLayer">Polyline geometry feature layer used to add the new features.</param> /// <param name="pointLayer">The geometries from the point layer are used as vertices for the new line features.</param> /// <returns></returns> private Task <bool> ConstructSamplePolylines(FeatureLayer polylineLayer, FeatureLayer pointLayer) { // execute the fine grained API calls on the CIM main thread return(QueuedTask.Run(() => { // get the underlying feature class for each layer var polylineFeatureClass = polylineLayer.GetTable() as FeatureClass; var pointFeatureClass = pointLayer.GetTable() as FeatureClass; // retrieve the feature class schema information for the feature classes var polylineDefinition = polylineFeatureClass.GetDefinition() as FeatureClassDefinition; var pointDefinition = pointFeatureClass.GetDefinition() as FeatureClassDefinition; // construct a cursor for all point features, since we want all feature there is no // QueryFilter required var pointCursor = pointFeatureClass.Search(null, false); var is3D = pointFeatureClass.GetDefinition().HasZ(); // initialize a counter variable int pointCounter = 0; // initialize a list to hold 5 coordinates that are used as vertices for the polyline var lineMapPoints = new List <MapPoint>(5); // set up the edit operation for the feature creation var createOperation = new EditOperation() { Name = "Create polylines", SelectNewFeatures = false }; // loop through the point features while (pointCursor.MoveNext()) { pointCounter++; var pointFeature = pointCursor.Current as Feature; // add the feature point geometry as a coordinate into the vertex list of the line // - ensure that the projection of the point geometry is converted to match the spatial reference of the line lineMapPoints.Add(((MapPoint)GeometryEngine.Instance.Project(pointFeature.GetShape(), polylineDefinition.GetSpatialReference()))); // for every 5 geometries, construct a new polyline and queue a feature create if (pointCounter % 5 == 0) { // construct a new polyline by using the 5 point coordinate in the current list var newPolyline = PolylineBuilderEx.CreatePolyline(lineMapPoints, polylineDefinition.GetSpatialReference()); // queue the create operation as part of the edit operation createOperation.Create(polylineLayer, newPolyline); // reset the list of coordinates lineMapPoints = new List <MapPoint>(5); } } // execute the edit (create) operation return createOperation.ExecuteAsync(); })); }
protected override Task <bool> OnSketchCompleteAsync(Geometry geometry) { //Run on MCT return(QueuedTask.Run(() => { //get the templates var map = MapView.Active.Map; IEnumerable <Layer> layers = map.GetLayersAsFlattenedList().AsEnumerable(); Layer mainLayer = layers.FirstOrDefault(l => l.Name == "main"); Layer mhLayer = layers.FirstOrDefault(l => l.Name == "manhole"); Layer conLayer = layers.FirstOrDefault(l => l.Name == "connector"); if ((mainLayer == null) || (mhLayer == null) || (conLayer == null)) { return false; } var mainTemplate = mainLayer.GetTemplate("main"); var mhTemplate = mhLayer.GetTemplate("manhole"); var conTemplate = conLayer.GetTemplate("connector"); if ((mainTemplate == null) || (mhTemplate == null) || (conTemplate == null)) { return false; } var op = new EditOperation() { Name = "Create main-connector-manhole", SelectModifiedFeatures = false, SelectNewFeatures = false }; //create the main geom var mainGeom = GeometryEngine.Instance.Move(geometry, 0, 0, -20); op.Create(mainTemplate, mainGeom); //create manhole points and connector foreach (var pnt in ((Polyline)geometry).Points) { //manhole point at sketch vertex op.Create(mhTemplate, pnt); //vertical connector between mahole and main var conPoints = new List <MapPoint> { pnt, //top of vertical connector GeometryEngine.Instance.Move(pnt, 0, 0, -20) as MapPoint //bottom of vertical connector }; var conPolyLine = PolylineBuilderEx.CreatePolyline(conPoints); op.Create(conTemplate, conPolyLine); } return op.Execute(); })); }
private Task OnBeforeSketchCompletedEvent(BeforeSketchCompletedEventArgs arg) { //replace curved sketch segments with straight segments //return if sketch geometry is not polygon or polyline if (!(arg.Sketch.GeometryType == GeometryType.Polyline || arg.Sketch.GeometryType == GeometryType.Polygon)) { return(Task.CompletedTask); } var sketchMP = arg.Sketch as Multipart; //if the sketch doesnt have curves then return if (!sketchMP.HasCurves) { return(Task.CompletedTask); } //itterate through each sketch part var newParts = new List <List <Segment> >(); foreach (var sketchPart in sketchMP.Parts) { //itterate through each sketch segment var newSegments = new List <Segment>(); foreach (var sketchSegment in sketchPart) { if (sketchSegment.IsCurve) { newSegments.Add(LineBuilderEx.CreateLineSegment(sketchSegment.StartPoint, sketchSegment.EndPoint)); } else { newSegments.Add(sketchSegment); } } newParts.Add(newSegments); } //create the new sketch geometry based on sketch type and set back on the sketch if (arg.Sketch.GeometryType == GeometryType.Polyline) { var polyline = PolylineBuilderEx.CreatePolyline(newParts, AttributeFlags.None); arg.SetSketchGeometry(polyline); } else { var polygon = PolygonBuilderEx.CreatePolygon(newParts, AttributeFlags.None); arg.SetSketchGeometry(polygon); } return(Task.CompletedTask); }
/// <summary> /// When the active map view changes, update the graphic overlay on the map control /// </summary> /// <param name="args"></param> private void OnMapViewCameraChanged(MapViewCameraChangedEventArgs args) { if (MapView.Active == null) { return; } if (MapView.Active.Extent == null) { return; } if (MapView.Active.ViewingMode != ArcGIS.Core.CIM.MapViewingMode.Map) { return; } //get the Map view's extent var viewExtent = MapView.Active.Extent.Clone() as Envelope; QueuedTask.Run(() => { //Line symbol to be used to draw the overview rectangle. if (_lineSymbol == null) { _lineSymbol = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.RedRGB, 2.0, SimpleLineStyle.Solid); } _graphic?.Dispose(); //Clear out the old overlay _overviewEnvelope = viewExtent; //overview envelope based on active map view if (_overviewEnvelope == null) { return; } //Creating the overview rectangle IList <MapPoint> segments = new List <MapPoint> { MapPointBuilderEx.CreateMapPoint(_overviewEnvelope.XMin, _overviewEnvelope.YMin, _overviewEnvelope.SpatialReference), MapPointBuilderEx.CreateMapPoint(_overviewEnvelope.XMax, _overviewEnvelope.YMin, _overviewEnvelope.SpatialReference), MapPointBuilderEx.CreateMapPoint(_overviewEnvelope.XMax, _overviewEnvelope.YMax, _overviewEnvelope.SpatialReference), MapPointBuilderEx.CreateMapPoint(_overviewEnvelope.XMin, _overviewEnvelope.YMax, _overviewEnvelope.SpatialReference), MapPointBuilderEx.CreateMapPoint(_overviewEnvelope.XMin, _overviewEnvelope.YMin, _overviewEnvelope.SpatialReference) }; _polyLine = PolylineBuilderEx.CreatePolyline(segments, AttributeFlags.None, _overviewEnvelope.SpatialReference); _graphic = _mapControl.AddOverlay(_polyLine, _lineSymbol.MakeSymbolReference()); }); }
/// <summary> /// Creates a new camera offset from the provided camera around an ellipse. /// </summary> /// <param name="camera">The starting camera.</param> /// <param name="ellipse">The ellipse around which the camera will rotate.</param> /// <param name="centerPoint">The center point of the ellipse.</param> /// <param name="percentAlong">The percentage around the ellipse to create the camera.</param> private Camera OffsetCamera(Camera camera, Polyline ellipse, MapPoint centerPoint, double percentAlong) { camera = CloneCamera(camera); var fromPoint = GeometryEngine.Instance.MovePointAlongLine(ellipse, percentAlong, true, 0, SegmentExtensionType.NoExtension); var segment = LineBuilderEx.CreateLineSegment(new Coordinate2D(centerPoint.X, centerPoint.Y), new Coordinate2D(fromPoint.X, centerPoint.Y), centerPoint.SpatialReference); var difX = GeometryEngine.Instance.GeodesicLength(PolylineBuilderEx.CreatePolyline(new Segment[] { segment }, AttributeFlags.None, segment.SpatialReference)); if (centerPoint.X - fromPoint.X < 0) { difX *= -1; } segment = LineBuilderEx.CreateLineSegment(new Coordinate2D(centerPoint.X, centerPoint.Y), new Coordinate2D(centerPoint.X, fromPoint.Y), centerPoint.SpatialReference); var difY = GeometryEngine.Instance.GeodesicLength(PolylineBuilderEx.CreatePolyline(new Segment[] { segment }, AttributeFlags.None, segment.SpatialReference)); if (centerPoint.Y - fromPoint.Y < 0) { difY *= -1; } var radian = Math.Atan2(difX, difY); var heading = radian * -180 / Math.PI; camera.Heading = heading; var difZ = centerPoint.Z - (camera.Z * ((camera.SpatialReference.IsGeographic) ? 1.0 : camera.SpatialReference.Unit.ConversionFactor)); var hypotenuse = GeometryEngine.Instance.GeodesicDistance(fromPoint, centerPoint); radian = Math.Atan2(difZ, hypotenuse); var pitch = radian * 180 / Math.PI; camera.Pitch = pitch; if (fromPoint.SpatialReference.Wkid != camera.SpatialReference.Wkid) { var transformation = ProjectionTransformation.Create(fromPoint.SpatialReference, camera.SpatialReference); fromPoint = GeometryEngine.Instance.ProjectEx(fromPoint, transformation) as MapPoint; } camera.X = fromPoint.X; camera.Y = fromPoint.Y; return(camera); }
/// <summary> /// Implement the on-click behavior of the individual menu items. Alternatively, addins can /// implement on-click behavior via a delegate assigned to each menu item (refer to the dynamic /// menu Add method overloads). /// </summary> /// <param name="index">The 0-based index of the clicked menu item</param> /// <remarks>Retrieve the feature geometry (for the clicked menu item) and /// append it into the sketch.</remarks> protected override void OnClick(int index) { if (_featureInfo == null) { return; } var fl = MapView.Active.Map.FindLayer(_featureInfo.Item1) as FeatureLayer; QueuedTask.Run(() => { //Use inspector to retrieve the feature shape var insp = new Inspector(); insp.Load(fl, _featureInfo.Item2[index]); //Project var temp_line = GeometryEngine.Instance.Project(insp["SHAPE"] as Polyline, MapView.Active.Map.SpatialReference) as Polyline; //Move the beginning of the shape to the right-click //location... var first_point = temp_line.Points[0]; var dx = _insertPoint.X - first_point.X; var dy = _insertPoint.Y - first_point.Y; var mv_line = GeometryEngine.Instance.Move(temp_line, dx, dy); //match the geometry sr with the sketch sr Polyline finalLine = GeometryEngine.Instance.Project(mv_line, _sketch.SpatialReference) as Polyline; //Sketch might be empty but it is never null... //assumes single part polyline here... var points = ((Polyline)_sketch).Points.ToList(); points.AddRange(finalLine.Points); var bldr = new PolylineBuilderEx(points.Select(p => p.Coordinate3D).ToList(), _sketch.SpatialReference); //ensure the geometry is Z enabled to be used as for //the sketch bldr.HasZ = true; _sketch = bldr.ToGeometry(); MapView.Active.SetCurrentSketchAsync(_sketch); }); }
/// <summary> /// Create sample polygon feature using the point geometries from the multi-point feature using the /// ConvexHull method provided by the GeometryEngine. /// </summary> /// <param name="polygonLayer">Polygon geometry feature layer used to add the new feature.</param> /// <param name="lineLayer">The polyline feature layer containing the features used to construct the polygon.</param> /// <returns></returns> private Task <bool> ConstructSamplePolygon(FeatureLayer polygonLayer, FeatureLayer lineLayer) { // execute the fine grained API calls on the CIM main thread return(QueuedTask.Run(() => { // get the underlying feature class for each layer var polygonFeatureClass = polygonLayer.GetTable() as FeatureClass; var polygonDefinition = polygonFeatureClass.GetDefinition() as FeatureClassDefinition; var lineFeatureClass = lineLayer.GetTable() as FeatureClass; // construct a cursor to retrieve the line features var lineCursor = lineFeatureClass.Search(null, false); // set up the edit operation for the feature creation var createOperation = new EditOperation() { Name = "Create polygons", SelectNewFeatures = false }; var polylineBuilder = new PolylineBuilderEx(polygonDefinition.GetSpatialReference()); while (lineCursor.MoveNext()) { // retrieve the first feature using (var lineFeature = lineCursor.Current as Feature) { // add the coordinate collection of the current geometry into our overall list of collections var polylineGeometry = lineFeature.GetShape() as Polyline; polylineBuilder.AddParts(polylineGeometry.Parts); } } // use the ConvexHull method from the GeometryEngine to construct the polygon geometry var newPolygon = GeometryEngine.Instance.ConvexHull(polylineBuilder.ToGeometry()) as Polygon; // queue the polygon creation createOperation.Create(polygonLayer, newPolygon); // execute the edit (polygon create) operation return createOperation.ExecuteAsync(); })); }
/// <summary> /// Called when the sketch finishes. This is where we will create the sketch operation and then execute it. /// </summary> /// <param name="geometry">The geometry created by the sketch.</param> /// <returns>A Task returning a Boolean indicating if the sketch complete event was successfully handled.</returns> protected override Task <bool> OnSketchCompleteAsync(Geometry geometry) { if (CurrentTemplate == null || geometry == null) { return(Task.FromResult(false)); } return(QueuedTask.Run(() => { //build a circular arc var cent = new Coordinate2D(geometry as MapPoint); var circleEAB = EllipticArcBuilderEx.CreateCircle(cent, Radius, ArcOrientation.ArcClockwise, MapView.Active.Map.SpatialReference); // find the source layer and determine whether polyline/polygon. Create the appropriate shape var lyr = CurrentTemplate.Layer as BasicFeatureLayer; Geometry circleGeom = null; if (lyr.ShapeType == esriGeometryType.esriGeometryPolygon) { circleGeom = PolygonBuilderEx.CreatePolygon(new[] { circleEAB }, AttributeFlags.None); } else { circleGeom = PolylineBuilderEx.CreatePolyline(circleEAB, AttributeFlags.None); } // Create an edit operation var createOperation = new EditOperation(); createOperation.Name = string.Format("Create circular {0}", CurrentTemplate.Layer.Name); createOperation.SelectNewFeatures = true; // Queue feature creation createOperation.Create(CurrentTemplate, circleGeom); // Execute the operation return createOperation.ExecuteAsync(); })); }
/// <summary> /// This method takes an input multi part geometry and breaks the parts into individual standalone geometries. /// This method must be called on the MCT. Use QueuedTask.Run. /// </summary> /// <param name="inputGeometry">The geometry to be exploded into the individual parts.</param> /// <returns>An enumeration of individual parts as standalone geometries. The type of geometry is maintained, i.e. /// if the input geometry is of type Polyline then each geometry in the return is of type Polyline as well. /// If the input geometry is of type Unknown then an empty list is returned.</returns> /// <remarks>This method must be called on the MCT. Use QueuedTask.Run.</remarks> public IEnumerable <Geometry> MultipartToSinglePart(Geometry inputGeometry) { // list holding the part(s) of the input geometry List <Geometry> singleParts = new List <Geometry>(); // check if the input is a null pointer or if the geometry is empty if (inputGeometry == null || inputGeometry.IsEmpty) { return(singleParts); } // based on the type of geometry, take the parts/points and add them individually into a list switch (inputGeometry.GeometryType) { case GeometryType.Envelope: singleParts.Add(inputGeometry.Clone() as Envelope); break; case GeometryType.Multipatch: singleParts.Add(inputGeometry.Clone() as Multipatch); break; case GeometryType.Multipoint: var multiPoint = inputGeometry as Multipoint; foreach (var point in multiPoint.Points) { // add each point of collection as a standalone point into the list singleParts.Add(point); } break; case GeometryType.Point: singleParts.Add(inputGeometry.Clone() as MapPoint); break; case GeometryType.Polygon: var polygon = inputGeometry as Polygon; foreach (var polygonPart in polygon.Parts) { // use the PolygonBuilder turning the segments into a standalone // polygon instance singleParts.Add(PolygonBuilderEx.CreatePolygon(polygonPart)); } break; case GeometryType.Polyline: var polyline = inputGeometry as Polyline; foreach (var polylinePart in polyline.Parts) { // use the PolylineBuilder turning the segments into a standalone // polyline instance singleParts.Add(PolylineBuilderEx.CreatePolyline(polylinePart)); } break; case GeometryType.Unknown: break; default: break; } return(singleParts); }
protected override async Task <bool> OnSketchCompleteAsync(Geometry geometry) { // get the embedded control var vm = this.EmbeddableControl as ChooseTemplateViewModel; if (vm == null) { return(false); } // ensure there's a template chosen if (vm.SelectedTemplate == null) { vm.ShowMessage("Please choose a layer and template"); return(false); } // clear any message vm.ClearMessage(); var template = vm.SelectedTemplate; BasicFeatureLayer templateLayer = template.Layer as BasicFeatureLayer; if (templateLayer == null) { return(false); } bool result = await QueuedTask.Run(() => { // find the target feature from the geometry click var targetFeatures = MapView.Active.GetFeatures(geometry); if ((targetFeatures == null) || (targetFeatures.ToDictionary().Keys.Count == 0)) { return(false); } // we will use the first feature returned var targetLayer = targetFeatures.ToDictionary().Keys.First(); var targetOID = targetFeatures[targetLayer][0]; // At 2.4, EditOperation.TransferAttributes method is one of the few functions which honors the field mapping. // The only method signature for EditOperation.TransferAttributes requires a source and target feature // So our workflow will be // 1. Create a temporary feature using the chosen template and empty geometry // 2. Call TransferAttributes from the temporary feature to the target feature // 3. Delete the temporary feature // build an empty geometry according to the correct template layer type Geometry emptyGeometry = null; switch (templateLayer.ShapeType) { case esriGeometryType.esriGeometryPoint: emptyGeometry = MapPointBuilderEx.CreateMapPoint(); break; case esriGeometryType.esriGeometryPolyline: emptyGeometry = PolylineBuilderEx.CreatePolyline(); break; case esriGeometryType.esriGeometryPolygon: emptyGeometry = PolygonBuilderEx.CreatePolygon(); break; } // some other geometry type if (emptyGeometry == null) { return(false); } // create the temporary feature using the empty geometry var op = new EditOperation(); op.Name = "Transfer attributes from template"; // note Create signature.. we are interested in the new ObjectID var rowToken = op.Create(template, emptyGeometry); // execute var opResult = op.Execute(); // if create was successful if (opResult) { var newObjectID = rowToken.ObjectID.Value; // chain to create a new operation var opChain = op.CreateChainedOperation(); // transfer the attributes between the temporary feature and the target feature opChain.TransferAttributes(templateLayer, newObjectID, targetLayer, targetOID); // and now delete the temporary feature opChain.Delete(templateLayer, newObjectID); opResult = opChain.Execute(); } return(opResult); }); return(result); }
protected override void OnClick() { //Selected voxel layer var voxelLayer = MapView.Active.GetSelectedLayers().OfType <VoxelLayer>().FirstOrDefault(); if (voxelLayer == null) { voxelLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType <VoxelLayer>().FirstOrDefault(); if (voxelLayer == null) { return; } } QueuedTask.Run(() => { if (voxelLayer.Visualization != VoxelVisualization.Surface) { voxelLayer.SetVisualization(VoxelVisualization.Surface); } voxelLayer.SetSectionContainerExpanded(true); voxelLayer.SetSectionContainerVisibility(true); //delete all sections var volume = voxelLayer.SelectedVariableProfile.Volume; foreach (var section in volume.GetSections()) { volume.DeleteSection(section); } var vol_size = volume.GetVolumeSize(); var voxel_pos = new Coordinate3D(0, 0, vol_size.Z); var voxel_pos_ur = new Coordinate3D(vol_size.X, vol_size.Y, vol_size.Z); //Make the diagonal in voxel space we will be using var lineBuilder = new LineBuilderEx(voxel_pos, voxel_pos_ur, null); var diagonal = PolylineBuilderEx.CreatePolyline(lineBuilder.ToSegment()); var num_sections = 12; var spacing = 1 / (double)num_sections; //change as needed var orientation = 20.0; var tilt = -15.0; var normal = voxelLayer.GetNormal(orientation, tilt); for (int s = 0; s < num_sections; s++) { Coordinate2D end_pt = new Coordinate2D(0, 0); if (s > 0) { //position each section along the diagonal var segments = new List <Segment>() as ICollection <Segment>; var part = GeometryEngine.Instance.GetSubCurve3D( diagonal, 0.0, s * spacing, AsRatioOrLength.AsRatio); part.GetAllSegments(ref segments); end_pt = segments.First().EndCoordinate; } volume.CreateSection(new SectionDefinition() { Name = $"Diagonal {s + 1}", VoxelPosition = new Coordinate3D(end_pt.X, end_pt.Y, vol_size.Z), Normal = normal, IsVisible = true }); } }); }
private void CreateTable(string tableName, string filePath) { _dataTable.TableName = tableName; var oidCol = new DataColumn(ObjectIdFieldName, typeof(Int32)) { AutoIncrement = true, AutoIncrementSeed = 1 }; _dataTable.Columns.Add(oidCol); _dataTable.PrimaryKey = new DataColumn[] { oidCol }; _dataTable.Columns.Add(new DataColumn(GeometryFieldName, typeof(ArcGIS.Core.Geometry.Geometry))); _dataTable.Columns.Add(new DataColumn(LongFieldName, typeof(Double))); _dataTable.Columns.Add(new DataColumn(LatFieldName, typeof(Double))); _dataTable.Columns.Add(new DataColumn(AltFieldName, typeof(Double))); if (_geomType == GeometryType.Polyline) { _dataTable.Columns.Add(new DataColumn(TypeFieldName, typeof(string))); _dataTable.Columns.Add(new DataColumn(DateTimeFieldName, typeof(DateTime))); _dataTable.Columns.Add(new DataColumn(NameFieldName, typeof(string))); _dataTable.Columns.Add(new DataColumn(CreatorFieldName, typeof(string))); _dataTable.Columns.Add(new DataColumn(CreatorVersionFieldName, typeof(string))); } else { _dataTable.Columns.Add(new DataColumn(TrkPntTime, typeof(DateTime))); _dataTable.Columns.Add(new DataColumn(TrkPntHr, typeof(Int32))); _dataTable.Columns.Add(new DataColumn(TrkPntCad, typeof(Int32))); } XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(filePath); string xmlns = xmlDoc.DocumentElement.NamespaceURI; XmlNamespaceManager nmsp = new XmlNamespaceManager(xmlDoc.NameTable); nmsp.AddNamespace("x", xmlns); DateTime dateValue = DateTime.Now; XmlNodeList nodeList = xmlDoc.DocumentElement.SelectNodes(@"//x:gpx/x:metadata/x:time", nmsp); if (nodeList.Count > 0) { var dateStr = nodeList[0].InnerText; try { dateValue = DateTime.Parse(dateStr); Console.WriteLine("'{0}' converted to {1}.", dateStr, dateValue); } catch (FormatException) { Console.WriteLine("Unable to convert '{0}'.", dateStr); } } var creator = string.Empty; var creatorVersion = string.Empty; nodeList = xmlDoc.DocumentElement.SelectNodes(@"//x:gpx", nmsp); if (nodeList.Count > 0) { var node = nodeList[0]; foreach (XmlAttribute attr in node.Attributes) { switch (attr.Name) { case "creator": creator = attr.Value; break; case "version": creatorVersion = attr.Value; break; } } } var activityName = string.Empty; var activityType = string.Empty; nodeList = xmlDoc.DocumentElement.SelectNodes("/x:gpx/x:trk/x:name", nmsp); if (nodeList.Count > 0) { activityName = nodeList[0].InnerText; } nodeList = xmlDoc.DocumentElement.SelectNodes("/x:gpx/x:trk/x:type", nmsp); if (nodeList.Count > 0) { activityType = nodeList[0].InnerText; } var newRow = _dataTable.NewRow(); var objectid = 1; // let's make a 3d line shape List <Coordinate3D> lst3DCoords = new List <Coordinate3D>(); double lng = 0.0, lat = 0.0, ele = 0.0; Int32 cad = -1, hr = -1; DateTime?trkTime = null; nodeList = xmlDoc.DocumentElement.SelectNodes("/x:gpx/x:trk/x:trkseg/x:trkpt", nmsp); foreach (XmlNode node in nodeList) { lng = double.Parse(node.Attributes["lon"].Value); lat = double.Parse(node.Attributes["lat"].Value); foreach (XmlNode childNode in node.ChildNodes) { switch (childNode.Name) { case "ele": ele = double.Parse(childNode.InnerText); break; case "time": trkTime = DateTime.Parse(childNode.InnerText); break; case "extensions": if (childNode.HasChildNodes) { foreach (XmlNode extNode in childNode.ChildNodes[0].ChildNodes) { switch (extNode.LocalName) { case "hr": hr = Int32.Parse(extNode.InnerText); break; case "cad": cad = Int32.Parse(extNode.InnerText); break; } } } break; } } if (_geomType == GeometryType.Polyline) { lst3DCoords.Add(new Coordinate3D(lng, lat, ele)); } else { // for the point variety we only have many rows newRow[ObjectIdFieldName] = objectid++; var mp = MapPointBuilderEx.CreateMapPoint(new Coordinate3D(lng, lat, ele), _spatialReference); newRow[GeometryFieldName] = mp; newRow[LongFieldName] = lng; newRow[LatFieldName] = lat; newRow[AltFieldName] = ele; if (trkTime.HasValue) { newRow[TrkPntTime] = trkTime.Value; } newRow[TrkPntHr] = hr; newRow[TrkPntCad] = cad; _dataTable.Rows.Add(newRow); _gisExtent = _gisExtent == null ? mp.Extent : _gisExtent.Union(mp.Extent); newRow = _dataTable.NewRow(); } } if (_geomType == GeometryType.Polyline) { // for the line variety we only have one row newRow[ObjectIdFieldName] = objectid; var pl = PolylineBuilderEx.CreatePolyline(lst3DCoords, _spatialReference); newRow[GeometryFieldName] = pl; newRow[LongFieldName] = lng; newRow[LatFieldName] = lat; newRow[AltFieldName] = ele; newRow[TypeFieldName] = activityType; newRow[DateTimeFieldName] = dateValue; newRow[NameFieldName] = activityName; newRow[CreatorFieldName] = creator; newRow[CreatorVersionFieldName] = creatorVersion; _dataTable.Rows.Add(newRow); _gisExtent = _gisExtent == null ? pl.Extent : _gisExtent.Union(pl.Extent); } }
/// <summary> /// Creates keyframes along the path using the user defined settings. /// </summary> /// <param name="line">The geometry of the line to fly along.</param> /// <param name="verticalUnit">The elevation unit of the 3D layer</param> internal Task CreateKeyframesAlongPath(Polyline line, Unit verticalUnit) { return(QueuedTask.Run(() => { var mapView = MapView.Active; if (mapView == null) { return; } //Get the camera track from the active map's animation. //There will always be only one camera track in the animation. var cameraTrack = mapView.Map.Animation.Tracks.OfType <CameraTrack>().First(); //Get some of the user settings for constructing the keyframes alone the path. var densifyDistance = Animation.Settings.KeyEvery; var verticalOffset = Animation.Settings.HeightAbove / ((mapView.Map.SpatialReference.IsGeographic) ? 1.0 : mapView.Map.SpatialReference.Unit.ConversionFactor); //1 meter double currentTimeSeconds = GetInsertTime(mapView.Map.Animation); //We need to project the line to a projected coordinate system to calculate the line's length in 3D //as well as more accurately calculated heading and pitch along the path. if (line.SpatialReference.IsGeographic) { if (mapView.Map.SpatialReference.IsGeographic) { var transformation = ProjectionTransformation.Create(line.SpatialReference, SpatialReferences.WebMercator, line.Extent); line = GeometryEngine.Instance.ProjectEx(line, transformation) as Polyline; } else { var transformation = ProjectionTransformation.Create(line.SpatialReference, mapView.Map.SpatialReference, line.Extent); line = GeometryEngine.Instance.ProjectEx(line, transformation) as Polyline; } } //If the user has specified to create keyframes at additional locations than just the vertices //we will densify the line by the distance the user specified. if (!Animation.Settings.VerticesOnly) { line = GeometryEngine.Instance.DensifyByLength(line, densifyDistance / line.SpatialReference.Unit.ConversionFactor) as Polyline; } //To maintain a constant speed we need to divide the total time we want the animation to take by the length of the line. var duration = Animation.Settings.Duration; var secondsPerUnit = duration / line.Length3D; Camera prevCamera = null; //Loop over each vertex in the line and create a new keyframe at each. for (int i = 0; i < line.PointCount; i++) { #region Camera MapPoint cameraPoint = line.Points[i]; //If the point is not in the same spatial reference of the map we need to project it. if (cameraPoint.SpatialReference.Wkid != mapView.Map.SpatialReference.Wkid) { var transformation = ProjectionTransformation.Create(cameraPoint.SpatialReference, mapView.Map.SpatialReference); cameraPoint = GeometryEngine.Instance.Project(cameraPoint, mapView.Map.SpatialReference) as MapPoint; } //Construct a new camera from the point. var camera = new Camera(cameraPoint.X, cameraPoint.Y, cameraPoint.Z, Animation.Settings.Pitch, 0.0, cameraPoint.SpatialReference, CameraViewpoint.LookFrom); //Convert the Z unit to meters if the camera is not in a geographic coordinate system. if (!camera.SpatialReference.IsGeographic) { camera.Z /= camera.SpatialReference.Unit.ConversionFactor; } //Convert the Z to the unit of the layer's elevation unit and then add the user defined offset from the line. camera.Z *= verticalUnit.ConversionFactor; camera.Z += verticalOffset; //If this is the last point in the collection use the same heading and pitch from the previous camera. if (i + 1 == line.Points.Count) { camera.Heading = prevCamera.Heading; camera.Pitch = prevCamera.Pitch; } else { var currentPoint = line.Points[i]; var nextPoint = line.Points[i + 1]; #region Heading //Calculate the heading from the current point to the next point in the path. var difX = nextPoint.X - currentPoint.X; var difY = nextPoint.Y - currentPoint.Y; var radian = Math.Atan2(difX, difY); var heading = radian * -180 / Math.PI; camera.Heading = heading; #endregion #region Pitch //If the user doesn't want to hardcode the pitch, calculate the pitch based on the current point to the next point. if (Animation.Settings.UseLinePitch) { var hypotenuse = Math.Sqrt(Math.Pow(difX, 2) + Math.Pow(difY, 2)); var difZ = nextPoint.Z - currentPoint.Z; //If the line's unit is not the same as the elevation unit of the layer we need to convert the Z so they are in the same unit. if (line.SpatialReference.Unit.ConversionFactor != verticalUnit.ConversionFactor) { difZ *= (verticalUnit.ConversionFactor / line.SpatialReference.Unit.ConversionFactor); } radian = Math.Atan2(difZ, hypotenuse); var pitch = radian * 180 / Math.PI; camera.Pitch = pitch; } else { camera.Pitch = Animation.Settings.Pitch; } #endregion } #endregion #region Time //The first point will have a time of 0 seconds, after that we need to set the time based on the 3D distance between the points. if (i > 0) { var lineSegment = PolylineBuilderEx.CreatePolyline(new List <MapPoint>() { line.Points[i - 1], line.Points[i] }, AttributeFlags.HasZ, line.SpatialReference); var length = lineSegment.Length3D; currentTimeSeconds += length * secondsPerUnit; } #endregion //Create a new keyframe using the camera and the time. cameraTrack.CreateKeyframe(camera, TimeSpan.FromSeconds(currentTimeSeconds), AnimationTransition.Linear); prevCamera = camera; } })); }