async public static void CreateElementSnippets() { //There are already many Create element snippets in the PRO snippets section. This section will only contain examples that are NOT in the Pro snippets section //Pro snippets region names includes: // Create point graphic with symbology // Create line graphic with symbology // Create rectangle graphic with simple symbology // Create text element with basic font properties // Create rectangle text with more advanced symbol settings // Create a new picture element with advanced symbol settings // Create a map frame and zoom to a bookmark // Create a legend for a specifc map frame // Creating group elements LayoutView lytView = LayoutView.Active; Layout layout = lytView.Layout; #region Create_BeizierCurve await QueuedTask.Run(() => { //Build geometry Coordinate2D pt1 = new Coordinate2D(1, 7.5); Coordinate2D pt2 = new Coordinate2D(1.66, 8); Coordinate2D pt3 = new Coordinate2D(2.33, 7.1); Coordinate2D pt4 = new Coordinate2D(3, 7.5); CubicBezierBuilder bez = new CubicBezierBuilder(pt1, pt2, pt3, pt4); CubicBezierSegment bezSeg = bez.ToSegment(); Polyline bezPl = PolylineBuilder.CreatePolyline(bezSeg); //Set symbology, create and add element to layout CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.RedRGB, 4.0, SimpleLineStyle.DashDot); GraphicElement bezElm = LayoutElementFactory.Instance.CreateLineGraphicElement(layout, bezPl, lineSym); bezElm.SetName("New Bezier Curve"); }); #endregion Create_BeizierCurve #region Create_freehand await QueuedTask.Run(() => { //Build geometry List <Coordinate2D> plCoords = new List <Coordinate2D>(); plCoords.Add(new Coordinate2D(1.5, 10.5)); plCoords.Add(new Coordinate2D(1.25, 9.5)); plCoords.Add(new Coordinate2D(1, 10.5)); plCoords.Add(new Coordinate2D(0.75, 9.5)); plCoords.Add(new Coordinate2D(0.5, 10.5)); plCoords.Add(new Coordinate2D(0.5, 1)); plCoords.Add(new Coordinate2D(0.75, 2)); plCoords.Add(new Coordinate2D(1, 1)); Polyline linePl = PolylineBuilder.CreatePolyline(plCoords); //Set symbolology, create and add element to layout CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Solid); GraphicElement lineElm = LayoutElementFactory.Instance.CreateLineGraphicElement(layout, linePl, lineSym); lineElm.SetName("New Freehand"); }); #endregion Create_freehand #region Create_polygon await QueuedTask.Run(() => { //Build geometry List <Coordinate2D> plyCoords = new List <Coordinate2D>(); plyCoords.Add(new Coordinate2D(1, 7)); plyCoords.Add(new Coordinate2D(2, 7)); plyCoords.Add(new Coordinate2D(2, 6.7)); plyCoords.Add(new Coordinate2D(3, 6.7)); plyCoords.Add(new Coordinate2D(3, 6.1)); plyCoords.Add(new Coordinate2D(1, 6.1)); Polygon poly = PolygonBuilder.CreatePolygon(plyCoords); //Set symbolology, create and add element to layout CIMStroke outline = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlueRGB, 2.0, SimpleLineStyle.DashDotDot); CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB, SimpleFillStyle.ForwardDiagonal, outline); GraphicElement polyElm = LayoutElementFactory.Instance.CreatePolygonGraphicElement(layout, poly, polySym); polyElm.SetName("New Polygon"); }); #endregion Create_polygon #region Create_circle await QueuedTask.Run(() => { //Build geometry Coordinate2D center = new Coordinate2D(2, 4); EllipticArcBuilder eabCir = new EllipticArcBuilder(center, 0.5, esriArcOrientation.esriArcClockwise); EllipticArcSegment cir = eabCir.ToSegment(); //Set symbolology, create and add element to layout CIMStroke outline = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Dash); CIMPolygonSymbol circleSym = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB, SimpleFillStyle.Solid, outline); GraphicElement cirElm = LayoutElementFactory.Instance.CreateCircleGraphicElement(layout, cir, circleSym); cirElm.SetName("New Circle"); }); #endregion Create_circle #region Create_ellipse await QueuedTask.Run(() => { //Build geometry Coordinate2D center = new Coordinate2D(2, 2.75); EllipticArcBuilder eabElp = new EllipticArcBuilder(center, 0, 1, 0.45, esriArcOrientation.esriArcClockwise); EllipticArcSegment ellipse = eabElp.ToSegment(); //Set symbolology, create and add element to layout CIMStroke outline = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.GreenRGB, 2.0, SimpleLineStyle.Dot); CIMPolygonSymbol ellipseSym = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.GreyRGB, SimpleFillStyle.Vertical, outline); GraphicElement elpElm = LayoutElementFactory.Instance.CreateEllipseGraphicElement(layout, ellipse, ellipseSym); elpElm.SetName("New Ellipse"); }); #endregion Create_ellipse #region Create_lasso await QueuedTask.Run(() => { //Build geometry List <Coordinate2D> plyCoords = new List <Coordinate2D>(); plyCoords.Add(new Coordinate2D(1, 1)); plyCoords.Add(new Coordinate2D(1.25, 2)); plyCoords.Add(new Coordinate2D(1.5, 1.1)); plyCoords.Add(new Coordinate2D(1.75, 2)); plyCoords.Add(new Coordinate2D(2, 1.1)); plyCoords.Add(new Coordinate2D(2.25, 2)); plyCoords.Add(new Coordinate2D(2.5, 1.1)); plyCoords.Add(new Coordinate2D(2.75, 2)); plyCoords.Add(new Coordinate2D(3, 1)); Polygon poly = PolygonBuilder.CreatePolygon(plyCoords); //Set symbolology, create and add element to layout CIMStroke outline = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Solid); CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB, SimpleFillStyle.ForwardDiagonal, outline); GraphicElement polyElm = LayoutElementFactory.Instance.CreatePolygonGraphicElement(layout, poly, polySym); polyElm.SetName("New Lasso"); }); #endregion Create_lasso #region Create_CurveText await QueuedTask.Run(() => { //Build geometry Coordinate2D pt1 = new Coordinate2D(3.6, 7.5); Coordinate2D pt2 = new Coordinate2D(4.26, 8); Coordinate2D pt3 = new Coordinate2D(4.93, 7.1); Coordinate2D pt4 = new Coordinate2D(5.6, 7.5); CubicBezierBuilder bez = new CubicBezierBuilder(pt1, pt2, pt3, pt4); CubicBezierSegment bezSeg = bez.ToSegment(); Polyline bezPl = PolylineBuilder.CreatePolyline(bezSeg); //Set symbolology, create and add element to layout CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(ColorFactory.Instance.BlackRGB, 24, "Comic Sans MS", "Regular"); GraphicElement bezTxtElm = LayoutElementFactory.Instance.CreateCurvedTextGraphicElement(layout, bezPl, "Curved Text", sym); bezTxtElm.SetName("New Splinned Text"); }); #endregion Create_CurveText #region Create_PolygonText await QueuedTask.Run(() => { //Build geometry List <Coordinate2D> plyCoords = new List <Coordinate2D>(); plyCoords.Add(new Coordinate2D(3.5, 7)); plyCoords.Add(new Coordinate2D(4.5, 7)); plyCoords.Add(new Coordinate2D(4.5, 6.7)); plyCoords.Add(new Coordinate2D(5.5, 6.7)); plyCoords.Add(new Coordinate2D(5.5, 6.1)); plyCoords.Add(new Coordinate2D(3.5, 6.1)); Polygon poly = PolygonBuilder.CreatePolygon(plyCoords); //Set symbolology, create and add element to layout CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(ColorFactory.Instance.GreyRGB, 10, "Arial", "Regular"); string text = "Some Text String that is really long and is <BOL>forced to wrap to other lines</BOL> so that we can see the effects." as String; GraphicElement polyTxtElm = LayoutElementFactory.Instance.CreatePolygonParagraphGraphicElement(layout, poly, text, sym); polyTxtElm.SetName("New Polygon Text"); //(Optionally) Modify paragraph border CIMGraphic polyTxtGra = polyTxtElm.Graphic; CIMParagraphTextGraphic cimPolyTxtGra = polyTxtGra as CIMParagraphTextGraphic; cimPolyTxtGra.Frame.BorderSymbol = new CIMSymbolReference(); cimPolyTxtGra.Frame.BorderSymbol.Symbol = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.GreyRGB, 1.0, SimpleLineStyle.Solid); polyTxtElm.SetGraphic(polyTxtGra); }); #endregion Create_PolygonText #region Create_CircleText await QueuedTask.Run(() => { //Build geometry Coordinate2D center = new Coordinate2D(4.5, 4); EllipticArcBuilder eabCir = new EllipticArcBuilder(center, 0.5, esriArcOrientation.esriArcClockwise); EllipticArcSegment cir = eabCir.ToSegment(); //Set symbolology, create and add element to layout CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(ColorFactory.Instance.GreenRGB, 10, "Arial", "Regular"); string text = "Circle, circle, circle, circle, circle, circle, circle, circle, circle, circle, circle"; GraphicElement cirTxtElm = LayoutElementFactory.Instance.CreateCircleParagraphGraphicElement(layout, cir, text, sym); cirTxtElm.SetName("New Circle Text"); //(Optionally) Modify paragraph border CIMGraphic cirTxtGra = cirTxtElm.Graphic; CIMParagraphTextGraphic cimCirTxtGra = cirTxtGra as CIMParagraphTextGraphic; cimCirTxtGra.Frame.BorderSymbol = new CIMSymbolReference(); cimCirTxtGra.Frame.BorderSymbol.Symbol = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.GreyRGB, 1.0, SimpleLineStyle.Solid); cirTxtElm.SetGraphic(cirTxtGra); }); #endregion Create_CircleText #region Create_EllipseText await QueuedTask.Run(() => { //Build geometry Coordinate2D center = new Coordinate2D(4.5, 2.75); EllipticArcBuilder eabElp = new EllipticArcBuilder(center, 0, 1, 0.45, esriArcOrientation.esriArcClockwise); EllipticArcSegment ellipse = eabElp.ToSegment(); //Set symbolology, create and add element to layout CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(ColorFactory.Instance.BlueRGB, 10, "Arial", "Regular"); string text = "Ellipse, ellipse, ellipse, ellipse, ellipse, ellipse, ellipse, ellipse, ellipse, ellipse, ellipse, ellipse"; GraphicElement elpTxtElm = LayoutElementFactory.Instance.CreateEllipseParagraphGraphicElement(layout, ellipse, text, sym); elpTxtElm.SetName("New Ellipse Text"); //(Optionally) Modify paragraph border CIMGraphic elpTxtGra = elpTxtElm.Graphic; CIMParagraphTextGraphic cimElpTxtGra = elpTxtGra as CIMParagraphTextGraphic; cimElpTxtGra.Frame.BorderSymbol = new CIMSymbolReference(); cimElpTxtGra.Frame.BorderSymbol.Symbol = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.GreyRGB, 1.0, SimpleLineStyle.Solid); elpTxtElm.SetGraphic(elpTxtGra); }); #endregion Create_EllipseText MapFrame mfElm = null; #region Create_MapFrame //This example creates a new map frame and changes the camera scale. await QueuedTask.Run(() => { //Build geometry Coordinate2D ll = new Coordinate2D(6.0, 8.5); Coordinate2D ur = new Coordinate2D(8.0, 10.5); Envelope env = EnvelopeBuilder.CreateEnvelope(ll, ur); //Reference map, create MF and add to layout MapProjectItem mapPrjItem = Project.Current.GetItems <MapProjectItem>().FirstOrDefault(item => item.Name.Equals("Map")); Map mfMap = mapPrjItem.GetMap(); mfElm = LayoutElementFactory.Instance.CreateMapFrame(layout, env, mfMap); mfElm.SetName("New Map Frame"); //Set the camera Camera camera = mfElm.Camera; camera.Scale = 24000; mfElm.SetCamera(camera); }); #endregion Create_MapFrame #region Create_ScaleBar await QueuedTask.Run(() => { //Reference a North Arrow in a style StyleProjectItem stylePrjItm = Project.Current.GetItems <StyleProjectItem>().FirstOrDefault(item => item.Name == "ArcGIS 2D"); ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars("Double Alternating Scale Bar 1")[0]; //Build geometry Coordinate2D center = new Coordinate2D(7, 8); //Reference MF, create north arrow and add to layout MapFrame mf = layout.FindElement("New Map Frame") as MapFrame; if (mf == null) { ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Map frame not found", "WARNING"); return; } ScaleBar sbElm = LayoutElementFactory.Instance.CreateScaleBar(layout, center, mf, sbStyleItm); sbElm.SetName("New Scale Bar"); sbElm.SetWidth(2); sbElm.SetX(6); sbElm.SetY(7.5); }); #endregion Create_ScaleBar #region Create_NorthArrow await QueuedTask.Run(() => { //Reference a North Arrow in a style StyleProjectItem stylePrjItm = Project.Current.GetItems <StyleProjectItem>().FirstOrDefault(item => item.Name == "ArcGIS 2D"); NorthArrowStyleItem naStyleItm = stylePrjItm.SearchNorthArrows("ArcGIS North 10")[0]; //Build geometry Coordinate2D center = new Coordinate2D(7, 5.5); //Reference MF, create north arrow and add to layout MapFrame mf = layout.FindElement("New Map Frame") as MapFrame; if (mf == null) { ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Map frame not found", "WARNING"); return; } NorthArrow arrowElm = LayoutElementFactory.Instance.CreateNorthArrow(layout, center, mf, naStyleItm); arrowElm.SetName("New North Arrow"); arrowElm.SetHeight(1.75); arrowElm.SetX(7); arrowElm.SetY(6); }); #endregion Create_NorthArrow }
//Use this method for smoother turns at corners. Additionally this method processes straight line segments and arc segments separately //For arc segments a keyframe is created at every second. However a minimum of 5 keyframes are created for arcs. //So if arc segment length is less than 5 then we default to at least 5 keyframes. This is an attempt to stick to the path as much as possible. //For straight line segments, rotation is ignored at end point of each segment except for the end point of the path itself. Two keyframes with rotation //are created at certain distance (determined by LINE_CONSTRAINT_FACTOR) before and after the end point of each segment. This is an attempt to avoid //sharp turns at corners along the path. public static async Task CreateKeyframes_AlongPath(MapView mapView, SpatialReference layerSpatRef, ProjectionTransformation transformation, CameraTrack cameraTrack, IEnumerator <ReadOnlySegmentCollection> segments, int segmentCount, double pathLength) { double segmentLength = 0; int num_iterations = 0; segments.Reset(); //process each segment depending upon its type - straight line or arc while (segments.MoveNext()) { ReadOnlySegmentCollection seg = segments.Current; double accumulatedDuration = mapView.Map.Animation.Duration.TotalSeconds + ((mapView.Map.Animation.Duration.TotalSeconds > 0) ? ANIMATION_APPEND_TIME : 0); // 0; foreach (Segment s in seg) { double length3D = Math.Sqrt((s.EndPoint.X - s.StartPoint.X) * (s.EndPoint.X - s.StartPoint.X) + (s.EndPoint.Y - s.StartPoint.Y) * (s.EndPoint.Y - s.StartPoint.Y) + (s.EndPoint.Z - s.StartPoint.Z) * (s.EndPoint.Z - s.StartPoint.Z)); double segmentDuration = (TotalDuration / pathLength) * length3D; segmentLength = length3D; //straight line segments if (s.SegmentType == SegmentType.Line) { MapPoint startPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.StartPoint.X, s.StartPoint.Y, s.StartPoint.Z *Z_CONVERSION_FACTOR, layerSpatRef)); MapPoint endPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.EndPoint.X, s.EndPoint.Y, s.EndPoint.Z *Z_CONVERSION_FACTOR, layerSpatRef)); //we will be creating three intermediate keyframes for staright segments only if segment length is more than a set threshold //the threshold is just a guess and might have to be altered depending upon the path geometry. Should work for most cases though MapPoint firstIntPoint = null; MapPoint midIntPoint = null; MapPoint lastIntPoint = null; if (segmentLength >= STRAIGHT_SEGMENT_LENGTH_THRESHOLD) { //first intermediate point firstIntPoint = await CreatePointAlongSegment(startPt, endPt, LINE_CONSTRAINT_FACTOR *segmentLength, layerSpatRef); //mid point midIntPoint = await CreatePointAlongSegment(startPt, endPt, 0.5 *segmentLength, layerSpatRef); //last intermediate point lastIntPoint = await CreatePointAlongSegment(startPt, endPt, (1 - LINE_CONSTRAINT_FACTOR) *segmentLength, layerSpatRef); } //create keyframe at start vertex of path in map space double timeSpanValue = accumulatedDuration; TimeSpan keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); if (segmentLength >= STRAIGHT_SEGMENT_LENGTH_THRESHOLD) { SetPitchAndHeadingForLine(startPt, firstIntPoint); } else { SetPitchAndHeadingForLine(startPt, endPt); } //ignore rotation for all start vertices (which would also be end vertices of previous segments) EXCEPT for the first vertex of path if (num_iterations == 0 || segmentLength < STRAIGHT_SEGMENT_LENGTH_THRESHOLD) { await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } else { await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading, true, false); } if (segmentLength > STRAIGHT_SEGMENT_LENGTH_THRESHOLD) { //Create a keyframe at PATH_CONSTRAINT_FACTOR distance along the segment from start point double distanceAlong = LINE_CONSTRAINT_FACTOR * segmentLength; timeSpanValue = accumulatedDuration + LINE_CONSTRAINT_FACTOR * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(firstIntPoint, midIntPoint); await CreateCameraKeyframe(mapView, firstIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at middle of segment distanceAlong = 0.5 * segmentLength; timeSpanValue = accumulatedDuration + 0.5 * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(midIntPoint, lastIntPoint); //await CreateCameraKeyframe(mapView, midIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at (1 - PATH_CONSTRAINT_FACTOR) distance along the segment from start point distanceAlong = (1 - LINE_CONSTRAINT_FACTOR) * segmentLength; timeSpanValue = accumulatedDuration + (1 - LINE_CONSTRAINT_FACTOR) * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(lastIntPoint, endPt); await CreateCameraKeyframe(mapView, lastIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } //Create a keyframe at end point of segment only for the end point of last segment //Otherwise we will get duplicate keyframes at end of one segment and start of the next one if (num_iterations == segmentCount - 1) { timeSpanValue = accumulatedDuration + segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); if (SelectedCameraView == "Face target") { SetPitchAndHeadingForLine(endPt, TargetPoint); } await CreateCameraKeyframe(mapView, endPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } } //processing for arcs - create a keyframe every second for arcs //we will create a minimum of 5 keyframes along the arc else if (s.SegmentType == SegmentType.EllipticArc && segmentDuration > 5) { EllipticArcSegment ellipArc = s as EllipticArcSegment; MapPoint startPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.StartPoint.X, s.StartPoint.Y, s.StartPoint.Z, layerSpatRef)); MapPoint endPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.EndPoint.X, s.EndPoint.Y, s.EndPoint.Z, layerSpatRef)); double radius = Math.Sqrt((ellipArc.CenterPoint.X - startPt.X) * (ellipArc.CenterPoint.X - startPt.X) + (ellipArc.CenterPoint.Y - startPt.Y) * (ellipArc.CenterPoint.Y - startPt.Y)); double angle = ellipArc.CentralAngle; MapPoint centerPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(ellipArc.CenterPoint.X, ellipArc.CenterPoint.Y, (s.StartPoint.Z + s.EndPoint.Z) / 2, layerSpatRef)); int num_keys = (int)segmentDuration; MapPoint firstIntPoint = null; //first intermediate keyframe for arc - needed for setting heading for start vertex // >2 to account for start and end if (num_keys > 2) { firstIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, angle / (num_keys - 1), radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); } //Create keyframe at start vertex of path in map space double timeSpanValue = accumulatedDuration; TimeSpan keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); if (firstIntPoint != null) { SetPitchAndHeadingForLine(startPt, firstIntPoint); } else { SetPitchAndHeadingForLine(startPt, endPt); } //Ignore rotation for all start vertices EXCEPT for the first vertex of path if (num_iterations == 0) { await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } else { await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading, true, false); } //Loop to create intermediate keyframes at each second for (int i = 0; i < num_keys - 2; i++) { MapPoint currentIntPoint = null; MapPoint nextIntPoint = null; currentIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, (angle / (num_keys - 1)) *(i + 1), radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); if (i < num_keys - 3) { nextIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, (angle / (num_keys - 1)) *(i + 2), radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); } else //for the last intermediate keyframe, heading/pitch has to be determined relative to the end point fo segment { nextIntPoint = endPt; } //timeSpanValue = accumulatedDuration + (i + 1) * 1; //at each second timeSpanValue = accumulatedDuration + (i + 1) * (segmentDuration / (num_keys - 1)); keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(currentIntPoint, nextIntPoint); await CreateCameraKeyframe(mapView, currentIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } //Create a keyframe at end point of segment only for the end point of last segment if (num_iterations == segmentCount - 1) { timeSpanValue = accumulatedDuration + segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); if (SelectedCameraView == "Face target") { SetPitchAndHeadingForLine(endPt, TargetPoint); } await CreateCameraKeyframe(mapView, endPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } } //create a minimum of 5 keyframes along the arc else if (s.SegmentType == SegmentType.EllipticArc) { EllipticArcSegment ellipArc = s as EllipticArcSegment; MapPoint startPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.StartPoint.X, s.StartPoint.Y, s.StartPoint.Z, layerSpatRef)); MapPoint endPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.EndPoint.X, s.EndPoint.Y, s.EndPoint.Z, layerSpatRef)); double radius = Math.Sqrt((ellipArc.CenterPoint.X - startPt.X) * (ellipArc.CenterPoint.X - startPt.X) + (ellipArc.CenterPoint.Y - startPt.Y) * (ellipArc.CenterPoint.Y - startPt.Y)); double angle = ellipArc.CentralAngle; MapPoint centerPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(ellipArc.CenterPoint.X, ellipArc.CenterPoint.Y, (s.StartPoint.Z + s.EndPoint.Z) / 2, layerSpatRef)); //we are creating five intermediate keyframes for arcs MapPoint firstIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, angle *ARC_CONSTRAINT_FACTOR, radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); MapPoint secondIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, angle *ARC_CONSTRAINT_FACTOR * 2, radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); MapPoint midIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, angle * 0.5, radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); MapPoint secondLastIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, angle *(1 - ARC_CONSTRAINT_FACTOR * 2), radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); MapPoint lastIntPoint = await CreatePointAlongArc(startPt, endPt, centerPt, angle *(1 - ARC_CONSTRAINT_FACTOR), radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); //Create keyframe at start vertex of path in map space double timeSpanValue = accumulatedDuration; TimeSpan keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(startPt, firstIntPoint); //Ignore rotation for all start vertices EXCEPT for the first vertex of path if (num_iterations == 0) { await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } else { await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading, true, false); } //await CreateCameraKeyframe(mapView, startPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at PATH_CONSTRAINT_FACTOR distance along the segment from start point timeSpanValue = accumulatedDuration + ARC_CONSTRAINT_FACTOR * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(firstIntPoint, secondIntPoint); await CreateCameraKeyframe(mapView, firstIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at 2* PATH_CONSTRAINT_FACTOR distance along the segment from start point timeSpanValue = accumulatedDuration + ARC_CONSTRAINT_FACTOR * 2 * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(secondIntPoint, midIntPoint); await CreateCameraKeyframe(mapView, secondIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at middle of segment timeSpanValue = accumulatedDuration + 0.5 * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(midIntPoint, secondLastIntPoint); await CreateCameraKeyframe(mapView, midIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at (1 - PATH_CONSTRAINT_FACTOR * 2) distance along the segment from start point timeSpanValue = accumulatedDuration + (1 - ARC_CONSTRAINT_FACTOR * 2) * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(secondLastIntPoint, lastIntPoint); await CreateCameraKeyframe(mapView, secondLastIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at (1 - PATH_CONSTRAINT_FACTOR) distance along the segment from start point timeSpanValue = accumulatedDuration + (1 - ARC_CONSTRAINT_FACTOR) * segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(lastIntPoint, endPt); await CreateCameraKeyframe(mapView, lastIntPoint, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); //Create a keyframe at end point of segment only for the end point of last segment if (num_iterations == segmentCount - 1) { timeSpanValue = accumulatedDuration + segmentDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); if (SelectedCameraView == "Face target") { SetPitchAndHeadingForLine(endPt, TargetPoint); } await CreateCameraKeyframe(mapView, endPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } } accumulatedDuration += segmentDuration; num_iterations++; } } }
//Use this method to create a keyframe at every n-second of the specified animation duration public static async Task CreateKeyframes_EveryNSeconds(MapView mapView, SpatialReference layerSpatRef, ProjectionTransformation transformation, CameraTrack cameraTrack, IEnumerator <ReadOnlySegmentCollection> segments, int segmentCount, double pathLength, double keyEveryNSecond = 1) { double segmentLength = 0; int numKeysToCreate = (int)(TotalDuration / keyEveryNSecond); //approximately double createKeyAtDist = pathLength / numKeysToCreate; double skippedDistance = 0; double accumulatedDuration = mapView.Map.Animation.Duration.TotalSeconds + ((mapView.Map.Animation.Duration.TotalSeconds > 0) ? ANIMATION_APPEND_TIME : 0); // 0; int num_iterations = 0; segments.Reset(); List <MapPoint> pointsForKeyframes = new List <MapPoint>(); MapPoint pathEndPt = null; //process each segment depending upon its type - straight line or arc while (segments.MoveNext()) { ReadOnlySegmentCollection seg = segments.Current; foreach (Segment s in seg) { segmentLength = Math.Sqrt((s.EndPoint.X - s.StartPoint.X) * (s.EndPoint.X - s.StartPoint.X) + (s.EndPoint.Y - s.StartPoint.Y) * (s.EndPoint.Y - s.StartPoint.Y) + (s.EndPoint.Z - s.StartPoint.Z) * (s.EndPoint.Z - s.StartPoint.Z)); double segmentDuration = (TotalDuration / pathLength) * segmentLength; //straight line segments if (s.SegmentType == SegmentType.Line) { MapPoint startPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.StartPoint.X, s.StartPoint.Y, s.StartPoint.Z, layerSpatRef)); MapPoint endPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.EndPoint.X, s.EndPoint.Y, s.EndPoint.Z, layerSpatRef)); //add start of path to points collection if (num_iterations == 0) { pointsForKeyframes.Add(startPt); } if (num_iterations == segmentCount - 1 || segmentCount == 1) { pathEndPt = endPt; //store path end pt. This will be the last keyframe. } double distCoveredAlongSeg = Math.Abs(createKeyAtDist - skippedDistance); //we are accouunting for skipped distances from previous segments if (distCoveredAlongSeg < segmentLength) { MapPoint keyPt = await CreatePointAlongSegment(startPt, endPt, distCoveredAlongSeg, layerSpatRef); //add point to collection pointsForKeyframes.Add(keyPt); //skipped distance is used now, reset to zero skippedDistance = 0; //are more keyframes possible for this segment bool moreKeysPossible = ((segmentLength - distCoveredAlongSeg) >= createKeyAtDist); while (moreKeysPossible) { double keyAtDistAlongSeg = distCoveredAlongSeg + createKeyAtDist; keyPt = await CreatePointAlongSegment(startPt, endPt, keyAtDistAlongSeg, layerSpatRef); //add point to collection pointsForKeyframes.Add(keyPt); distCoveredAlongSeg += createKeyAtDist; moreKeysPossible = ((segmentLength - distCoveredAlongSeg) > createKeyAtDist); } //if any segment length left then add to skipped distance skippedDistance += (segmentLength - distCoveredAlongSeg); } else { //add this segment's length to skipped distance as no keyframe could be created along it skippedDistance += segmentLength; } } else if (s.SegmentType == SegmentType.EllipticArc) { EllipticArcSegment ellipArc = s as EllipticArcSegment; MapPoint startPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.StartPoint.X, s.StartPoint.Y, s.StartPoint.Z, layerSpatRef)); MapPoint endPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(s.EndPoint.X, s.EndPoint.Y, s.EndPoint.Z, layerSpatRef)); double radius = Math.Sqrt((ellipArc.CenterPoint.X - startPt.X) * (ellipArc.CenterPoint.X - startPt.X) + (ellipArc.CenterPoint.Y - startPt.Y) * (ellipArc.CenterPoint.Y - startPt.Y)); double angle = ellipArc.CentralAngle; MapPoint centerPt = await QueuedTask.Run(() => MapPointBuilder.CreateMapPoint(ellipArc.CenterPoint.X, ellipArc.CenterPoint.Y, (s.StartPoint.Z + s.EndPoint.Z) / 2, layerSpatRef)); //add start of path to points collection if (num_iterations == 0) { pointsForKeyframes.Add(startPt); } if (num_iterations == segmentCount - 1 || segmentCount == 1) { pathEndPt = endPt; //store path end pt. This will be the last keyframe. } double distCoveredAlongSeg = Math.Abs(createKeyAtDist - skippedDistance); //we are accouunting for skipped distances from previous segments if (distCoveredAlongSeg < segmentLength) { MapPoint keyPt = await CreatePointAlongArc(startPt, endPt, centerPt, angle *distCoveredAlongSeg / segmentLength, radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); //add point to collection pointsForKeyframes.Add(keyPt); //skipped distance is used now, reset to zero skippedDistance = 0; //are more keyframes possible for this segment bool moreKeysPossible = ((segmentLength - distCoveredAlongSeg) >= createKeyAtDist); while (moreKeysPossible) { double keyAtDistAlongSeg = distCoveredAlongSeg + createKeyAtDist; keyPt = await CreatePointAlongArc(startPt, endPt, centerPt, angle *keyAtDistAlongSeg / segmentLength, radius, layerSpatRef, ellipArc.IsMinor, ellipArc.IsCounterClockwise); //add point to collection pointsForKeyframes.Add(keyPt); distCoveredAlongSeg += createKeyAtDist; moreKeysPossible = ((segmentLength - distCoveredAlongSeg) > createKeyAtDist); } //if any segment length left then add to skipped distance skippedDistance += (segmentLength - distCoveredAlongSeg); } else { //add this segment's length to skipped distance as no keyframe could be created along it skippedDistance += segmentLength; } } num_iterations++; } } //now iterate over the points list and create keyframes double timeSpanValue = accumulatedDuration; TimeSpan keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); for (int i = 0; i < pointsForKeyframes.Count; i++) { MapPoint currentPt = pointsForKeyframes[i]; MapPoint nextPt = null; if (i + 1 < pointsForKeyframes.Count) { nextPt = pointsForKeyframes[i + 1]; } else { nextPt = pathEndPt; } timeSpanValue = i * keyEveryNSecond + accumulatedDuration; keyframeTimespan = TimeSpan.FromSeconds(timeSpanValue); SetPitchAndHeadingForLine(currentPt, nextPt); await CreateCameraKeyframe(mapView, currentPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); if (i == pointsForKeyframes.Count - 1 && skippedDistance > 0) { keyframeTimespan = TimeSpan.FromSeconds(TotalDuration + accumulatedDuration); await CreateCameraKeyframe(mapView, pathEndPt, transformation, cameraTrack, keyframeTimespan, _keyframePitch, _keyframeHeading); } } }
/// <summary> /// Returns a polygon with a range fan(circular ring sector - like a donut wedge or wiper blade swipe with inner and outer radius) /// from the input parameters /// Input Angles must be 0-360 degrees /// </summary> public static Geometry ConstructRangeFan(MapPoint centerPoint, double innerDistanceInMapUnits, double outerDistanceInMapUnits, double horizontalStartAngleInBearing, double horizontalEndAngleInBearing, SpatialReference sr, double incrementAngleStep = 1.0) { // Check inputs if ((centerPoint == null) || (sr == null) || (innerDistanceInMapUnits < 0.0) || (outerDistanceInMapUnits < 0.0) || (horizontalStartAngleInBearing < 0.0) || (horizontalStartAngleInBearing > 360.0) || (horizontalEndAngleInBearing < 0.0) || (horizontalEndAngleInBearing > 360.0)) { return(null); } // Tricky - if angle cuts across 360, need to adjust for this case (ex. Angle: 270->90) if (horizontalStartAngleInBearing > horizontalEndAngleInBearing) { horizontalStartAngleInBearing = -(360.0 - horizontalStartAngleInBearing); } double deltaAngle = Math.Abs(horizontalStartAngleInBearing - horizontalEndAngleInBearing); // if full circle(or greater), return donut section with inner/outer rings if ((deltaAngle == 0.0) || (deltaAngle >= 360.0)) { // Just add 2 concentric circle buffers PolygonBuilder donutPb = new PolygonBuilder(); EllipticArcSegment circularArcOuter = EllipticArcBuilder.CreateEllipticArcSegment((Coordinate2D)centerPoint, outerDistanceInMapUnits, esriArcOrientation.esriArcClockwise, sr); donutPb.AddPart(new List <Segment> { circularArcOuter }); if (innerDistanceInMapUnits > 0.0) { EllipticArcSegment circularArcInner = EllipticArcBuilder.CreateEllipticArcSegment((Coordinate2D)centerPoint, innerDistanceInMapUnits, esriArcOrientation.esriArcCounterClockwise, sr); donutPb.AddPart(new List <Segment> { circularArcInner }); } return(donutPb.ToGeometry()); } // Otherwise if range fan, construct that var points = new List <MapPoint>(); MapPoint startPoint = null; if (innerDistanceInMapUnits <= 0.0) { startPoint = centerPoint; points.Add(startPoint); } double minAngle = Math.Min(horizontalStartAngleInBearing, horizontalEndAngleInBearing); double maxAngle = Math.Max(horizontalStartAngleInBearing, horizontalEndAngleInBearing); // don't let this create more than 360 points per arc if ((deltaAngle / incrementAngleStep) > 360.0) { incrementAngleStep = deltaAngle / 360.0; } // Draw Outer Arc of Ring // Implementation Note: because of the unique shape of this ring, // it was easier to manually create these points than use EllipticArcBuilder for (double angle = minAngle; angle <= maxAngle; angle += incrementAngleStep) { double cartesianAngle = (450 - angle) % 360; double angleInRadians = cartesianAngle * (Math.PI / 180.0); double x = centerPoint.X + (outerDistanceInMapUnits * Math.Cos(angleInRadians)); double y = centerPoint.Y + (outerDistanceInMapUnits * Math.Sin(angleInRadians)); MapPoint pointToAdd = MapPointBuilder.CreateMapPoint(x, y, sr); points.Add(pointToAdd); if (startPoint == null) { startPoint = pointToAdd; } } if (innerDistanceInMapUnits > 0.0) { // Draw Inner Arc of Ring - if inner distance set for (double angle = maxAngle; angle >= minAngle; angle -= incrementAngleStep) { double cartesianAngle = (450 - angle) % 360; double angleInRadians = cartesianAngle * (Math.PI / 180.0); double x = centerPoint.X + (innerDistanceInMapUnits * Math.Cos(angleInRadians)); double y = centerPoint.Y + (innerDistanceInMapUnits * Math.Sin(angleInRadians)); points.Add(MapPointBuilder.CreateMapPoint(x, y, sr)); } } // close Polygon points.Add(startPoint); PolygonBuilder pb = new PolygonBuilder(); pb.AddPart(points); return(pb.ToGeometry()); }