示例#1
0
        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());
        }