/// <summary>
        /// Returns all polygon points from given airspace polygon object
        /// </summary>
        /// <param name="polygon">airspace polygon</param>
        /// <param name="floor">floor altitude</param>
        /// <returns>position list object with all polygon points</returns>
        private static Czml.PositionList GetPolygonPointsFromAirspacePolygon(Airspace.Polygon polygon, Altitude floor)
        {
            double height = HeightFromAltitude(floor);

            var positions = new Czml.PositionList();

            foreach (var segment in polygon.Segments)
            {
                if (segment is Airspace.Polygon.PolygonPoint point)
                {
                    positions.Add(point.Point.Latitude, point.Point.Longitude, height);
                }

                if (segment is Airspace.Polygon.PolygonArc arc)
                {
                    var convertedArcSegment = ConvertPolygonArcToArcSegment(arc, height);
                    AddArcSegmentPolygonPoints(convertedArcSegment, positions, height);

                    positions.Add(arc.End.Latitude, arc.End.Longitude, height);
                }

                if (segment is Airspace.Polygon.PolygonArcSegment arcSegment)
                {
                    AddArcSegmentPolygonPoints(arcSegment, positions, height);
                }
            }

            return(positions);
        }
        /// <summary>
        /// Creates a Czml.Object from given airspace
        /// </summary>
        /// <param name="airspace">airspace to use</param>
        /// <returns>created CZML object</returns>
        private static Czml.Object CzmlObjectFromAirspace(Airspace.Airspace airspace)
        {
            double height = HeightFromAltitude(airspace.Ceiling) - HeightFromAltitude(airspace.Floor);

            if (airspace.Geometry is Circle circle)
            {
                return(new Czml.Object
                {
                    Name = airspace.Name,
                    Description = DescriptionFromAirspace(airspace),
                    Position = PositionFromCoord(circle.Center, airspace.Floor),
                    Cylinder = new Czml.Cylinder
                    {
                        BottomRadius = circle.Radius,
                        TopRadius = circle.Radius,
                        Length = height,
                        HeightReference = HeightReferenceFromAltitude(airspace.Floor),
                        Material = MaterialFromAirspace(airspace),
                        Outline = true,
                        OutlineColor = ColorFromAirspace(airspace, outlineColor: true),
                    },
                });
            }

            if (airspace.Geometry is Airspace.Polygon polygon)
            {
                Czml.PositionList positions = GetPolygonPointsFromAirspacePolygon(polygon, airspace.Floor);

                if (!positions.CartographicDegrees.Any())
                {
                    return(null);
                }

                return(new Czml.Object
                {
                    Name = airspace.Name,
                    Description = DescriptionFromAirspace(airspace),
                    Polygon = new Czml.Polygon
                    {
                        Positions = positions,
                        Height = HeightFromAltitude(airspace.Floor),
                        ExtrudedHeight = HeightFromAltitude(airspace.Ceiling),
                        HeightReference = HeightReferenceFromAltitude(airspace.Floor),
                        Material = MaterialFromAirspace(airspace),
                        Outline = true,
                        OutlineColor = ColorFromAirspace(airspace, outlineColor: true),
                    },
                });
            }

            throw new FormatException("invalid airspace geometry");
        }
        /// <summary>
        /// Generates all points for a PolygonArcSegment object and adds it to the positions
        /// </summary>
        /// <param name="arcSegment">arc segment to use</param>
        /// <param name="positions">positions to add to</param>
        /// <param name="height">height value</param>
        private static void AddArcSegmentPolygonPoints(
            Airspace.Polygon.PolygonArcSegment arcSegment,
            Czml.PositionList positions,
            double height)
        {
            var center = arcSegment.Center.ToMapPoint(height);

            bool isClockwise = arcSegment.Direction == Airspace.Polygon.ArcDirection.Clockwise;

            double endAngle   = arcSegment.EndAngle;
            double startAngle = arcSegment.StartAngle;

            // adjust angles so that we don't have to deal with wrap around
            if (isClockwise && startAngle > endAngle)
            {
                endAngle += 360.0;
            }

            if (!isClockwise && startAngle < endAngle)
            {
                startAngle += 360.0;
            }

            bool   isAtEnd;
            double step    = (isClockwise ? 1.0 : -1.0) * ArcSegmentAngleStepByRadius(arcSegment.Radius);
            double bearing = startAngle;

            do
            {
                var point = center.PolarOffset(arcSegment.Radius, -bearing, height);
                positions.Add(point.Latitude, point.Longitude, height);

                bearing += step;
                isAtEnd  = isClockwise
                    ? bearing > endAngle
                    : bearing < endAngle;
            }while (!isAtEnd);

            // add end point when the step angle didn't hit the end angle directly
            if (Math.Abs(bearing - arcSegment.EndAngle) > 1e-6)
            {
                var point = center.PolarOffset(arcSegment.Radius, -arcSegment.EndAngle, height);
                positions.Add(point.Latitude, point.Longitude, height);
            }
        }