Beispiel #1
0
        private const float WorldUwpMinScale = 96; // Above this: UWP shown above name

        #endregion Fields

        #region Constructors

        public Stylesheet(double scale, MapOptions options, Style style)
        {
            float onePixel = 1f / (float)scale;

            grayscale = false;
            lightBackground = false;

            subsectorGrid.visible = ((scale >= SubsectorsMinScale) && options.HasFlag(MapOptions.SubsectorGrid));
            sectorGrid.visible = ((scale >= SectorGridMinScale) && options.HasFlag(MapOptions.SectorGrid));
            parsecGrid.visible = (scale >= ParsecMinScale);
            showSomeSectorNames = ((scale >= SectorNameMinScale) && (scale <= SectorNameMaxScale) && ((options & MapOptions.SectorsMask) != 0));
            showAllSectorNames = showSomeSectorNames && ((scale >= SectorNameAllSelectedScale) || options.HasFlag(MapOptions.SectorsAll));
            subsectorNames.visible = ((scale >= SubsectorNameMinScale) && (scale <= SubsectorNameMaxScale) && ((options & MapOptions.SectorsMask) != 0));

            worlds.visible = (scale >= WorldMinScale);
            pseudoRandomStars.visible = (PseudoRandomStarsMinScale <= scale) && (scale <= PseudoRandomStarsMaxScale);
            showRifts = (scale <= PseudoRandomStarsMaxScale || style == Style.Candy);

            t5AllegianceCodes = scale >= T5AllegianceCodeMinScale;

            float logscale = (float)Math.Log(scale, 2.0);
            riftOpacity = ScaleInterpolate(0f, 0.85f, scale, 1/4f, 4f);

            deepBackgroundOpacity = ScaleInterpolate(1f, 0f, scale, 1/8f, 2f);

            macroRoutes.visible = (scale >= MacroRouteMinScale) && (scale <= MacroRouteMaxScale);
            macroNames.visible = (scale >= MacroLabelMinScale) && (scale <= MacroLabelMaxScale);
            megaNames.visible = scale <= MegaLabelMaxScale && ((options & MapOptions.NamesMask) != 0);
            showMicroNames = ((scale >= MicroNameMinScale) && ((options & MapOptions.NamesMask) != 0));
            capitals.visible = (scale >= MacroWorldsMinScale) && (scale <= MacroWorldsMaxScale);

            hexStyle = (((options & MapOptions.ForceHexes) == 0) && (scale < ParsecHexMinScale))
                ? HexStyle.Square
                : HexStyle.Hex;
            microBorderStyle = hexStyle == HexStyle.Square ? MicroBorderStyle.Square : MicroBorderStyle.Hex;

            macroBorders.visible = (scale >= MacroBorderMinScale) && (scale < MicroBorderMinScale) && ((options & MapOptions.BordersMask) != 0);
            microBorders.visible = (scale >= MicroBorderMinScale) && ((options & MapOptions.BordersMask) != 0);
            fillMicroBorders = microBorders.visible && options.HasFlag(MapOptions.FilledBorders);
            microRoutes.visible = (scale >= RouteMinScale);

            worldDetails = !worlds.visible ? WorldDetails.None :
                (scale < WorldBasicMinScale) ? WorldDetails.Dotmap :
                (scale < WorldFullMinScale) ? WorldDetails.Atlas :
                WorldDetails.Poster;

            showWorldDetailColors = worldDetails == WorldDetails.Poster && options.HasFlag(MapOptions.WorldColors);

            lowerCaseAllegiance = (scale < WorldFullMinScale);

            worlds.textBackgroundStyle = TextBackgroundStyle.Rectangle;

            hexCoordinateStyle = HexCoordinateStyle.Sector;
            numberAllHexes = false;

            if (scale < WorldFullMinScale)
            {
                // Atlas-style

                const float x = 0.225f;
                const float y = 0.125f;

                BaseTopPosition.X = -x;
                BaseTopPosition.Y = -y;
                BaseBottomPosition.X = -x;
                BaseBottomPosition.Y = y;
                GasGiantPosition.X = x;
                GasGiantPosition.Y = -y;
                AllegiancePosition.X = x;
                AllegiancePosition.Y = y;

                BaseMiddlePosition.X = options.HasFlag(MapOptions.ForceHexes) ? -0.35f : -0.2f;
                BaseMiddlePosition.Y = 0;
                StarportPosition.X = 0.0f;
                StarportPosition.Y = -0.24f;
                worlds.position.X = 0.0f;
                worlds.position.Y = 0.4f;
            }
            else
            {
                // Poster-style

                const float x = 0.25f;
                const float y = 0.18f;

                BaseTopPosition.X = -x;
                BaseTopPosition.Y = -y;
                BaseBottomPosition.X = -x;
                BaseBottomPosition.Y = y;
                GasGiantPosition.X = x;
                GasGiantPosition.Y = -y;
                AllegiancePosition.X = x;
                AllegiancePosition.Y = y;

                BaseMiddlePosition.X = -0.35f;
                BaseMiddlePosition.Y = 0f;
                StarportPosition.X = 0f;
                StarportPosition.Y = -0.225f;
                worlds.position.X = 0.0f;
                worlds.position.Y = 0.37f; // Don't hide hex bottom, leave room for UWP
            }

            if (scale >= WorldUwpMinScale)
            {
                worldDetails |= WorldDetails.Uwp;
                BaseBottomPosition.Y = 0.1f;
                BaseMiddlePosition.Y = (BaseBottomPosition.Y + BaseTopPosition.Y) / 2;
                AllegiancePosition.Y = 0.1f;
            }

            if (worlds.visible)
            {
                float fontScale = (scale <= 96f || style == Style.Candy) ? 1f : 96f / Math.Min((float)scale, 192f);

                worlds.fontInfo = new FontInfo(DEFAULT_FONT, scale < WorldFullMinScale ? 0.2f : 0.15f * fontScale, XFontStyle.Bold);
                wingdingFont = new FontInfo("Wingdings", scale < WorldFullMinScale ? 0.2f : 0.175f * fontScale);
                glyphFont = new FontInfo(DEFAULT_FONT, scale < WorldFullMinScale ? 0.175f : 0.15f * fontScale, XFontStyle.Bold);
                hexNumber.fontInfo = new FontInfo(DEFAULT_FONT, 0.1f * fontScale);
                worlds.smallFontInfo = new FontInfo(DEFAULT_FONT, scale < WorldFullMinScale ? 0.2f : 0.1f * fontScale, XFontStyle.Regular);
                worlds.largeFontInfo = worlds.fontInfo;
                starportFont = (scale < WorldFullMinScale) ? worlds.smallFontInfo : worlds.fontInfo;
            }

            sectorName.fontInfo = new FontInfo(DEFAULT_FONT, 5.5f);
            subsectorNames.fontInfo = new FontInfo(DEFAULT_FONT, 1.5f);

            microBorders.fontInfo = new FontInfo(DEFAULT_FONT, (scale == MicroNameMinScale) ? 0.6f : 0.25f, XFontStyle.Bold);
            microBorders.smallFontInfo = new FontInfo(DEFAULT_FONT, 0.15f, XFontStyle.Bold);
            microBorders.largeFontInfo = new FontInfo(DEFAULT_FONT, 0.75f, XFontStyle.Bold);

            macroNames.fontInfo = new FontInfo(DEFAULT_FONT, 8f / 1.4f, XFontStyle.Bold);
            macroNames.smallFontInfo = new FontInfo(DEFAULT_FONT, 5f / 1.4f, XFontStyle.Regular);
            macroNames.mediumFontInfo = new FontInfo(DEFAULT_FONT, 6.5f / 1.4f, XFontStyle.Italic);

            float megaNameScaleFactor = 1.0f * onePixel;
            megaNames.fontInfo = new FontInfo(DEFAULT_FONT, 24f * megaNameScaleFactor, XFontStyle.Bold);
            megaNames.mediumFontInfo = new FontInfo(DEFAULT_FONT, 22f * megaNameScaleFactor, XFontStyle.Regular);
            megaNames.smallFontInfo = new FontInfo(DEFAULT_FONT, 20f * megaNameScaleFactor, XFontStyle.Italic);

            capitals.fillColor = Color.Wheat;
            capitals.textColor = Color.Red;
            blueZone.pen.color = Color.Blue;
            amberZone.pen.color = Color.Gold;
            redZone.pen.color = Color.Red;
            macroBorders.pen.color = Color.Red;
            macroRoutes.pen.color = Color.White;
            microBorders.pen.color = Color.Gray;
            Color gridColor = Color.FromArgb(ScaleInterpolate(0, 255, scale, SectorGridMinScale, SectorGridFullScale), Color.Gray);
            microRoutes.pen.color = Color.Gray;

            Color foregroundColor = Color.White;
            backgroundColor = Color.Black;
            Color lightColor = Color.LightGray;
            Color darkColor = Color.DarkGray;
            Color dimColor = Color.DimGray;
            Color highlightColor = Color.Red;
            microBorders.textColor = Color.Gold;
            worldWater.fillColor = Color.DeepSkyBlue;
            worldNoWater.fillColor = Color.White;
            worldNoWater.pen.color = Color.Empty;

            parsecGrid.pen = new PenInfo(gridColor, onePixel);
            subsectorGrid.pen = new PenInfo(gridColor, onePixel * 2);
            sectorGrid.pen = new PenInfo(gridColor, (subsectorGrid.visible ? 4 : 2) * onePixel);
            worldWater.pen = new PenInfo(Color.Empty, Math.Max(0.01f, onePixel));

            microBorders.textStyle.Rotation = 0;
            microBorders.textStyle.Translation = new PointF(0, 0);
            microBorders.textStyle.Scale = new SizeF(1.0f, 1.0f);
            microBorders.textStyle.Uppercase = false;

            sectorName.textStyle.Rotation = -50; // degrees
            sectorName.textStyle.Translation = new PointF(0, 0);
            sectorName.textStyle.Scale = new SizeF(0.75f, 1.0f);
            sectorName.textStyle.Uppercase = false;
            sectorName.textStyle.Wrap = true;

            subsectorNames.textStyle = sectorName.textStyle;

            worlds.textStyle.Rotation = 0;
            worlds.textStyle.Scale = new SizeF(1.0f, 1.0f);
            worlds.textStyle.Translation = worlds.position;
            worlds.textStyle.Uppercase = false;

            useBackgroundImage = false;
            useGalaxyImage = deepBackgroundOpacity > 0.0f;
            useWorldImages = false;

            // Cap pen widths when zooming in
            float penScale = (scale <= 64) ? 1f : (64f / (float)scale);

            float borderPenWidth =
                (scale < MicroBorderMinScale) ? 1 : // When rendering vector borders
                (scale < ParsecMinScale) ? 1 :      // When not rendering "hexes"
                0.16f * penScale; // ... but cut in half by clipping

            float routePenWidth =
                scale <= 16 ? 0.2f :
                0.08f * penScale;

            microBorders.pen.width = borderPenWidth;
            macroBorders.pen.width = borderPenWidth;
            microRoutes.pen.width = routePenWidth;

            amberZone.pen.width = redZone.pen.width = blueZone.pen.width = 0.05f * penScale;

            macroRoutes.pen.width = borderPenWidth;
            macroRoutes.pen.DashStyle = XDashStyle.Dash;

            switch (style)
            {
                case Style.Poster:
                    {
                        // This is the default - no changes
                        break;
                    }
                case Style.Atlas:
                    {
                        grayscale = true;
                        lightBackground = true;

                        capitals.fillColor = Color.DarkGray;
                        capitals.textColor = Color.Black;
                        amberZone.pen.color = Color.LightGray;
                        blueZone.pen.color = Color.Gray; // TODO: make dashed
                        redZone.pen.color = Color.Black;
                        macroBorders.pen.color = Color.Black;
                        macroRoutes.pen.color = Color.Gray;
                        microBorders.pen.color = Color.Black;
                        microRoutes.pen.color = Color.Gray;

                        foregroundColor = Color.Black;
                        backgroundColor = Color.White;
                        lightColor = Color.DarkGray;
                        darkColor = Color.DarkGray;
                        dimColor = Color.LightGray;
                        highlightColor = Color.Gray;
                        microBorders.textColor = Color.Gray;
                        worldWater.fillColor = Color.Black;
                        worldNoWater.fillColor = Color.Empty;

                        worldNoWater.fillColor = Color.White;
                        worldNoWater.pen = new PenInfo(Color.Black, onePixel);

                        riftOpacity = Math.Min(riftOpacity, 0.70f);

                        showWorldDetailColors = false;

                        break;
                    }
                case Style.FASA:
                    {
                        useGalaxyImage = false;
                        deepBackgroundOpacity = 0f;
                        riftOpacity = 0;

                        Color inkColor = Color.FromArgb(0x5C, 0x40, 0x33);

                        foregroundColor = inkColor;
                        backgroundColor = Color.White;

                        grayscale = true; // TODO: Tweak to be "monochrome"
                        lightBackground = true;

                        capitals.fillColor = inkColor;
                        capitals.textColor = inkColor;
                        amberZone.pen.color = inkColor;
                        amberZone.pen.width = onePixel * 2;
                        blueZone.pen.color = inkColor; // TODO: make dashed
                        redZone.pen.color = Color.Empty;
                        redZone.fillColor = Color.FromArgb(0x80, inkColor);

                        macroBorders.pen.color = inkColor;
                        macroRoutes.pen.color = inkColor;

                        microBorders.pen.color = inkColor;
                        microBorders.pen.width = onePixel * 2;
                        microBorders.fontInfo.size *= 0.6f;
                        microBorders.fontInfo.style = XFontStyle.Regular;

                        microRoutes.pen.color = inkColor;

                        lightColor = Color.FromArgb(0x80, inkColor);
                        darkColor = inkColor;
                        dimColor = inkColor;
                        highlightColor = inkColor;
                        microBorders.textColor = inkColor;
                        hexStyle = HexStyle.Hex;
                        microBorderStyle = MicroBorderStyle.Curve;

                        parsecGrid.pen.color = lightColor;
                        sectorGrid.pen.color = lightColor;
                        subsectorGrid.pen.color = lightColor;

                        worldWater.fillColor = inkColor;
                        worldNoWater.fillColor = inkColor;
                        worldWater.pen.color = Color.Empty;
                        worldNoWater.pen.color = Color.Empty;

                        showWorldDetailColors = false;

                        worldDetails = worldDetails & ~WorldDetails.Starport;
                        worldDetails = worldDetails & ~WorldDetails.Allegiance;
                        worldDetails = worldDetails & ~WorldDetails.Bases;
                        worldDetails = worldDetails & ~WorldDetails.GasGiant;
                        worldDetails = worldDetails & ~WorldDetails.Highlight;
                        worlds.fontInfo.size *= 0.85f;
                        worlds.textStyle.Translation = new PointF(0, 0.25f);

                        numberAllHexes = true;
                        hexCoordinateStyle = HexCoordinateStyle.Subsector;
                        overrideLineStyle = LineStyle.Solid;

                        break;
                    }
                case Style.Print:
                    {
                        lightBackground = true;

                        foregroundColor = Color.Black;
                        backgroundColor = Color.White;
                        lightColor = Color.DarkGray;
                        darkColor = Color.DarkGray;
                        dimColor = Color.LightGray;
                        microRoutes.pen.color = Color.Gray;

                        microBorders.textColor = Color.Brown;

                        amberZone.pen.color = Color.Gold;
                        worldNoWater.fillColor = Color.White;
                        worldNoWater.pen = new PenInfo(Color.Black, onePixel);

                        riftOpacity = Math.Min(riftOpacity, 0.70f);

                        break;
                    }
                case Style.Draft:
                    {
                        int inkOpacity = 0xB0;

                        useGalaxyImage = false;
                        lightBackground = true;

                        deepBackgroundOpacity = 0f;

                        backgroundColor = Color.AntiqueWhite;
                        foregroundColor = Color.FromArgb(inkOpacity, Color.Black);
                        highlightColor = Color.FromArgb(inkOpacity, Color.Red);

                        lightColor = Color.FromArgb(inkOpacity, Color.DarkCyan);
                        darkColor = Color.FromArgb(inkOpacity, Color.Black);
                        dimColor = Color.FromArgb(inkOpacity / 2, Color.Black);

                        subsectorGrid.pen.color = Color.FromArgb(inkOpacity, Color.Firebrick);

                        const string FONT_NAME = "Comic Sans MS";
                        worlds.fontInfo.name = FONT_NAME;
                        worlds.smallFontInfo.name = FONT_NAME;
                        starportFont.name = FONT_NAME;
                        worlds.largeFontInfo.name = FONT_NAME;
                        worlds.largeFontInfo.size = worlds.fontInfo.size * 1.25f;
                        worlds.fontInfo.size *= 0.8f;

                        macroNames.fontInfo.name = FONT_NAME;
                        macroNames.mediumFontInfo.name = FONT_NAME;
                        macroNames.smallFontInfo.name = FONT_NAME;
                        megaNames.fontInfo.name = FONT_NAME;
                        megaNames.mediumFontInfo.name = FONT_NAME;
                        megaNames.smallFontInfo.name = FONT_NAME;
                        microBorders.smallFontInfo.name = FONT_NAME;
                        microBorders.largeFontInfo.name = FONT_NAME;
                        microBorders.fontInfo.name = FONT_NAME;
                        macroBorders.fontInfo.name = FONT_NAME;
                        macroRoutes.fontInfo.name = FONT_NAME;
                        capitals.fontInfo.name = FONT_NAME;
                        macroBorders.smallFontInfo.name = FONT_NAME;

                        microBorders.textStyle.Uppercase = true;

                        sectorName.textStyle.Uppercase = true;
                        subsectorNames.textStyle.Uppercase = true;

                        // TODO: Render small, around edges
                        subsectorNames.visible = false;

                        worlds.textStyle.Uppercase = true;

                        // TODO: Decide on this. It's nice to not overwrite the parsec grid, but
                        // it looks very cluttered, especially amber/red zones.
                        worlds.textBackgroundStyle = TextBackgroundStyle.None;

                        worldDetails = worldDetails & ~WorldDetails.Allegiance;

                        subsectorNames.fontInfo.name = FONT_NAME;
                        sectorName.fontInfo.name = FONT_NAME;

                        worlds.largeFontInfo.style |= XFontStyle.Underline;

                        microBorders.pen.width = onePixel * 4;
                        microBorders.pen.dashStyle = XDashStyle.Dot;

                        worldNoWater.fillColor = foregroundColor;
                        worldWater.fillColor = Color.Empty;
                        worldWater.pen = new PenInfo(foregroundColor, onePixel * 2);

                        amberZone.pen.color = foregroundColor;
                        amberZone.pen.width = onePixel;
                        redZone.pen.width = onePixel * 2;

                        microRoutes.pen.color = Color.Gray;

                        parsecGrid.pen.color = lightColor;
                        microBorders.textColor = Color.FromArgb(inkOpacity, Color.Brown);

                        riftOpacity = Math.Min(riftOpacity, 0.30f);

                        numberAllHexes = true;

                        break;
                    }
                case Style.Candy:
                    {
                        useWorldImages = true;
                        pseudoRandomStars.visible = false;

                        useBackgroundImage = deepBackgroundOpacity < 0.5f;

                        hexStyle = HexStyle.None;
                        microBorderStyle = MicroBorderStyle.Curve;

                        sectorGrid.visible = sectorGrid.visible && (scale >= 4);
                        subsectorGrid.visible = subsectorGrid.visible && (scale >= 32);
                        parsecGrid.visible = false;

                        subsectorGrid.pen.width = 0.03f * (64.0f / (float)scale);
                        subsectorGrid.pen.DashPattern = new double[] { 10.0, 8.0 };

                        sectorGrid.pen.width = 0.03f * (64.0f / (float)scale);
                        sectorGrid.pen.DashPattern = new double[] { 10.0, 8.0 };

                        worlds.textBackgroundStyle = TextBackgroundStyle.Shadow;

                        worldDetails = worldDetails
                            & ~WorldDetails.Starport & ~WorldDetails.Allegiance & ~WorldDetails.Bases & ~WorldDetails.Hex;

                        if (scale < CandyMinWorldNameScale)
                            worldDetails = worldDetails & ~WorldDetails.KeyNames & ~WorldDetails.AllNames;
                        if (scale < CandyMinUwpScale)
                            worldDetails = worldDetails & ~WorldDetails.Uwp;

                        amberZone.pen.color = Color.Goldenrod;

                        sectorName.textStyle.Rotation = 0;
                        sectorName.textStyle.Translation = new PointF(0, -0.25f);
                        sectorName.textStyle.Scale = new SizeF(0.5f, 0.25f);
                        sectorName.textStyle.Uppercase = true;

                        subsectorNames.textStyle.Rotation = 0;
                        subsectorNames.textStyle.Translation = new PointF(0, -0.25f);
                        subsectorNames.textStyle.Scale = new SizeF(0.3f, 0.15f); // Expand
                        subsectorNames.textStyle.Uppercase = true;

                        microBorders.textStyle.Rotation = 0;
                        microBorders.textStyle.Translation = new PointF(0, 0.25f);
                        microBorders.textStyle.Scale = new SizeF(1.0f, 0.5f); // Expand
                        microBorders.textStyle.Uppercase = true;

                        microBorders.pen.color = Color.FromArgb(128, Color.Red);

                        worlds.textStyle.Rotation = 0;
                        worlds.textStyle.Scale = new SizeF(1f, 0.5f); // Expand
                        worlds.textStyle.Translation = new PointF(0, 0);
                        worlds.textStyle.Uppercase = true;

                        if (scale > CandyMaxWorldRelativeScale)
                            hexContentScale = CandyMaxWorldRelativeScale / (float)scale;

                        break;
                    }
            }

            sectorName.textColor = scale < 16 ? foregroundColor :
                scale < 48 ? darkColor : dimColor;
            subsectorNames.textColor = scale < 16 ? foregroundColor :
                scale < 48 ? darkColor : dimColor;

            if (style == Style.Candy)
            {
                subsectorNames.textColor = sectorName.textColor = Color.FromArgb(128, Color.Goldenrod);

                amberZone.pen.width = redZone.pen.width = blueZone.pen.width = 0.035f;

                microRoutes.pen.width = scale < CandyMaxRouteRelativeScale ? routePenWidth : routePenWidth / 2;
                macroBorders.pen.width = scale < CandyMaxBorderRelativeScale ? borderPenWidth : borderPenWidth / 4;
                microBorders.pen.width = scale < CandyMaxBorderRelativeScale ? borderPenWidth : borderPenWidth / 4;
            }

            preferredMimeType = (style == Style.Candy)
                ? System.Net.Mime.MediaTypeNames.Image.Jpeg
                : Util.MediaTypeName_Image_Png;

            pseudoRandomStars.fillColor = foregroundColor;

            megaNames.textColor = foregroundColor;
            megaNames.textHighlightColor = highlightColor;

            macroNames.textColor = foregroundColor;
            macroNames.textHighlightColor = highlightColor;

            macroRoutes.textColor = foregroundColor;
            macroRoutes.textHighlightColor = highlightColor;

            worlds.textColor = foregroundColor;
            worlds.textHighlightColor = highlightColor;

            hexNumber.textColor = lightColor;
            imageBorderColor = lightColor;

            placeholder.content = "*";
            placeholder.fontInfo = new FontInfo("Georgia", 0.6f);
            placeholder.textColor = foregroundColor;
            placeholder.position = new PointF(0, 0.17f);
        }
        private const float WorldUwpMinScale = 96; // Above this: UWP shown above name

        #endregion Fields

        #region Constructors

        public Stylesheet(double scale, MapOptions options, Style style)
        {
            grayscale = false;
            subsectorGrid.visible = ((scale >= SubsectorsMinScale) && options.HasFlag(MapOptions.SubsectorGrid));
            sectorGrid.visible = ((scale >= SectorGridMinScale) && options.HasFlag(MapOptions.SectorGrid));
            parsecGrid.visible = (scale >= ParsecMinScale);
            showSomeSectorNames = ((scale >= SectorNameMinScale) && (scale <= SectorNameMaxScale) && ((options & MapOptions.SectorsMask) != 0));
            showAllSectorNames = showSomeSectorNames && ((scale >= SectorNameAllSelectedScale) || options.HasFlag(MapOptions.SectorsAll));
            subsectorNames.visible = ((scale >= SubsectorNameMinScale) && (scale <= SubsectorNameMaxScale) && ((options & MapOptions.SectorsMask) != 0));

            worlds.visible = (scale >= WorldMinScale);
            pseudoRandomStars.visible = (PseudoRandomStarsMinScale <= scale) && (scale <= PseudoRandomStarsMaxScale);
            showRifts = (scale <= PseudoRandomStarsMaxScale || style == Style.Candy);

            float logscale = (float)Math.Log(scale, 2.0);
            riftOpacity = Util.Clamp((logscale - -2f) / (2f - -2f), 0.0f, 1.0f) * 0.85f;
            deepBackgroundOpacity = 1.0f - Util.Clamp((logscale - -3f) / (0f - -3f), 0f, 1f);

            macroRoutes.visible = (scale >= MacroRouteMinScale) && (scale <= MacroRouteMaxScale);
            macroNames.visible = (scale >= MacroLabelMinScale) && (scale <= MacroLabelMaxScale);
            showMicroNames = ((scale >= MicroNameMinScale) && ((options & MapOptions.NamesMask) != 0));
            capitals.visible = (scale >= MacroWorldsMinScale) && (scale <= MacroWorldsMaxScale);

            microBorderStyle = (((options & MapOptions.ForceHexes) == 0) && (scale < ParsecHexMinScale))
                ? MicroBorderStyle.Square
                : MicroBorderStyle.Hex;

            macroBorders.visible = (scale >= MacroBorderMinScale) && (scale < MicroBorderMinScale) && ((options & MapOptions.BordersMask) != 0);
            microBorders.visible = (scale >= MicroBorderMinScale) && ((options & MapOptions.BordersMask) != 0);
            fillMicroBorders = microBorders.visible && options.HasFlag(MapOptions.FilledBorders);
            microRoutes.visible = (scale >= RouteMinScale);

            worldDetails = !worlds.visible ? 0 :
                (scale < WorldBasicMinScale) ? WorldDetails.Dotmap :
                (scale < WorldFullMinScale) ? WorldDetails.Atlas :
                WorldDetails.Poster;

            showWorldDetailColors = worldDetails == WorldDetails.Poster && options.HasFlag(MapOptions.WorldColors);

            lowerCaseAllegiance = (scale < WorldFullMinScale);

            worlds.textBackgroundStyle = TextBackgroundStyle.Rectangle;

            hexCoordinateStyle = HexCoordinateStyle.Sector;

            if (scale < WorldFullMinScale)
            {
                // Atlas-style

                const float x = 0.225f;
                const float y = 0.125f;

                BaseTopPosition.X = -x;
                BaseTopPosition.Y = -y;
                BaseBottomPosition.X = -x;
                BaseBottomPosition.Y = y;
                GasGiantPosition.X = x;
                GasGiantPosition.Y = -y;
                AllegiancePosition.X = x;
                AllegiancePosition.Y = y;

                BaseMiddlePosition.X = options.HasFlag(MapOptions.ForceHexes) ? -0.35f : -0.2f;
                BaseMiddlePosition.Y = 0;
                StarportPosition.X = 0.0f;
                StarportPosition.Y = -0.24f;
                worlds.position.X = 0.0f;
                worlds.position.Y = 0.4f;
            }
            else
            {
                // Poster-style

                const float x = 0.25f;
                const float y = 0.18f;

                BaseTopPosition.X = -x;
                BaseTopPosition.Y = -y;
                BaseBottomPosition.X = -x;
                BaseBottomPosition.Y = y;
                GasGiantPosition.X = x;
                GasGiantPosition.Y = -y;
                AllegiancePosition.X = x;
                AllegiancePosition.Y = y;

                BaseMiddlePosition.X = -0.35f;
                BaseMiddlePosition.Y = 0f;
                StarportPosition.X = 0f;
                StarportPosition.Y = -0.225f;
                worlds.position.X = 0.0f;
                worlds.position.Y = 0.37f; // Don't hide hex bottom, leave room for UWP
            }

            if (scale >= WorldUwpMinScale)
            {
                worldDetails |= WorldDetails.Uwp;
                BaseBottomPosition.Y = 0.1f;
                BaseMiddlePosition.Y = (BaseBottomPosition.Y + BaseTopPosition.Y) / 2;
                AllegiancePosition.Y = 0.1f;
            }

            if (worlds.visible)
            {
                float fontScale = (scale <= 96f || style == Style.Candy) ? 1f : 96f / (float)scale;

                worlds.fontInfo = new FontInfo(DEFAULT_FONT, scale < WorldFullMinScale ? 0.2f : 0.15f * fontScale, XFontStyle.Bold);
                wingdingFont = new FontInfo("Wingdings", scale < WorldFullMinScale ? 0.2f : 0.175f * fontScale);
                glyphFont = new FontInfo(DEFAULT_FONT, scale < WorldFullMinScale ? 0.175f : 0.15f * fontScale, XFontStyle.Bold);
                hexNumber.fontInfo = new FontInfo(DEFAULT_FONT, 0.1f * fontScale);
                worlds.smallFontInfo = new FontInfo(DEFAULT_FONT, scale < WorldFullMinScale ? 0.2f : 0.1f * fontScale, XFontStyle.Regular);
                starportFont = (scale < WorldFullMinScale) ? worlds.smallFontInfo : worlds.fontInfo;
            }

            sectorName.fontInfo = new FontInfo(DEFAULT_FONT, 5.5f);
            subsectorNames.fontInfo = new FontInfo(DEFAULT_FONT, 1.5f);

            microBorders.fontInfo = new FontInfo(DEFAULT_FONT, (scale == MicroNameMinScale) ? 0.6f : 0.25f, XFontStyle.Bold);
            microBorders.smallFontInfo = new FontInfo(DEFAULT_FONT, 0.15f, XFontStyle.Bold);
            microBorders.largeFontInfo = new FontInfo(DEFAULT_FONT, 0.75f, XFontStyle.Bold);

            macroNames.fontInfo = new FontInfo(DEFAULT_FONT, 8f / 1.4f, XFontStyle.Bold);
            macroNames.smallFontInfo = new FontInfo(DEFAULT_FONT, 5f / 1.4f, XFontStyle.Regular);

            capitals.fillColor = Color.Wheat;
            capitals.textColor = Color.Red;
            blueZone.pen.color = Color.Blue;
            amberZone.pen.color = Color.Gold;
            redZone.pen.color = Color.Red;
            macroBorders.pen.color = Color.Red;
            macroRoutes.pen.color = Color.White;
            microBorders.pen.color = Color.Gray;
            Color gridColor = Color.Gray;
            microRoutes.pen.color = Color.Green;

            Color foregroundColor = Color.White;
            backgroundColor = Color.Black;
            Color lightColor = Color.LightGray;
            Color darkColor = Color.DarkGray;
            Color dimColor = Color.DimGray;
            Color highlightColor = Color.Red;
            microBorders.textColor = Color.Gold;
            worldWater.fillColor = Color.DeepSkyBlue;
            worldNoWater.fillColor = Color.White;
            worldNoWater.pen.color = Color.Empty;

            float onePixel = 1f / (float)scale;

            parsecGrid.pen = new PenInfo(gridColor, onePixel);
            subsectorGrid.pen = new PenInfo(gridColor, onePixel * 2);
            sectorGrid.pen = new PenInfo(gridColor, (subsectorGrid.visible ? 4 : 2) * onePixel);

            microBorders.textStyle.Rotation = 0;
            microBorders.textStyle.Translation = new PointF(0, 0);
            microBorders.textStyle.Scale = new SizeF(1.0f, 1.0f);
            microBorders.textStyle.Uppercase = false;

            sectorName.textStyle.Rotation = -50;
            sectorName.textStyle.Translation = new PointF(0, 0);
            sectorName.textStyle.Scale = new SizeF(0.75f, 1.0f);
            sectorName.textStyle.Uppercase = false;
            sectorName.textStyle.Wrap = true;

            subsectorNames.textStyle = sectorName.textStyle;

            worlds.textStyle.Rotation = 0;
            worlds.textStyle.Scale = new SizeF(1.0f, 1.0f);
            worlds.textStyle.Translation = worlds.position;
            worlds.textStyle.Uppercase = false;

            useBackgroundImage = false;
            useGalaxyImage = false;
            useWorldImages = false;

            switch (style)
            {
                case Style.Poster:
                    {
                        // This is the default - no changes
                        useGalaxyImage = deepBackgroundOpacity > 0.0f;
                        break;
                    }
                case Style.Atlas:
                    {
                        deepBackgroundOpacity = 0f;

                        grayscale = true;
                        capitals.fillColor = Color.DarkGray;
                        capitals.textColor = Color.Black;
                        amberZone.pen.color = Color.LightGray;
                        blueZone.pen.color = Color.Gray; // TODO: make dashed
                        redZone.pen.color = Color.Black;
                        macroBorders.pen.color = Color.Black;
                        macroRoutes.pen.color = Color.Gray;
                        microBorders.pen.color = Color.Black;
                        microRoutes.pen.color = Color.Gray;

                        foregroundColor = Color.Black;
                        backgroundColor = Color.White;
                        lightColor = Color.DarkGray;
                        darkColor = Color.DarkGray;
                        dimColor = Color.LightGray;
                        highlightColor = Color.Gray;
                        microBorders.textColor = Color.Gray;
                        worldWater.fillColor = Color.Black;
                        worldNoWater.fillColor = Color.Empty;

                        worldNoWater.fillColor = Color.White;
                        worldNoWater.pen = new PenInfo(Color.Black, onePixel);

                        riftOpacity = Math.Min(riftOpacity, 0.70f);

                        showWorldDetailColors = false;

                        break;
                    }
                case Style.Print:
                    {
                        deepBackgroundOpacity = 0f;

                        foregroundColor = Color.Black;
                        backgroundColor = Color.White;
                        lightColor = Color.DarkGray;
                        darkColor = Color.DarkGray;
                        dimColor = Color.LightGray;
                        microRoutes.pen.color = Color.Gray;

                        microBorders.textColor = Color.Brown;

                        amberZone.pen.color = Color.Gold;
                        worldNoWater.fillColor = Color.White;
                        worldNoWater.pen = new PenInfo(Color.Black, onePixel);

                        riftOpacity = Math.Min(riftOpacity, 0.70f);

                        break;
                    }
                case Style.Candy:
                    {
                        useWorldImages = true;
                        pseudoRandomStars.visible = false;

                        useBackgroundImage = deepBackgroundOpacity < 1.0f;
                        useGalaxyImage = deepBackgroundOpacity > 0.0f;

                        microBorderStyle = MicroBorderStyle.Curve;

                        sectorGrid.visible = sectorGrid.visible && (scale >= 4 && scale < 32);
                        subsectorGrid.visible = subsectorGrid.visible && (scale >= 32);
                        parsecGrid.visible = false;

                        subsectorGrid.pen.width = 0.03f * (64.0f / (float)scale);
                        subsectorGrid.pen.DashPattern = new double[] { 10.0, 8.0 };

                        sectorGrid.pen.width = 0.03f * (64.0f / (float)scale);
                        sectorGrid.pen.DashPattern = new double[] { 10.0, 8.0 };

                        worlds.textBackgroundStyle = TextBackgroundStyle.Shadow;

                        worldDetails = worldDetails
                            & ~WorldDetails.Starport & ~WorldDetails.Allegiance & ~WorldDetails.Bases & ~WorldDetails.Hex;

                        if (scale < CandyMinWorldNameScale)
                            worldDetails = worldDetails & ~WorldDetails.KeyNames & ~WorldDetails.AllNames;
                        if (scale < CandyMinUwpScale)
                            worldDetails = worldDetails & ~WorldDetails.Uwp;

                        amberZone.pen.color = Color.Goldenrod;

                        sectorName.textStyle.Rotation = 0;
                        sectorName.textStyle.Translation = new PointF(0, -0.25f);
                        sectorName.textStyle.Scale = new SizeF(0.5f, 0.25f);
                        sectorName.textStyle.Uppercase = true;

                        subsectorNames.textStyle.Rotation = 0;
                        subsectorNames.textStyle.Translation = new PointF(0, -0.25f);
                        subsectorNames.textStyle.Scale = new SizeF(0.3f, 0.15f); // Expand
                        subsectorNames.textStyle.Uppercase = true;

                        microBorders.textStyle.Rotation = 0;
                        microBorders.textStyle.Translation = new PointF(0, 0.25f);
                        microBorders.textStyle.Scale = new SizeF(1.0f, 0.5f); // Expand
                        microBorders.textStyle.Uppercase = true;

                        microBorders.pen.color = Color.FromArgb(128, Color.Red);

                        worlds.textStyle.Rotation = 0;
                        worlds.textStyle.Scale = new SizeF(1f, 0.5f); // Expand
                        worlds.textStyle.Translation = new PointF(0, 0);
                        worlds.textStyle.Uppercase = true;

                        if (scale > CandyMaxWorldRelativeScale)
                        {
                            hexContentScale = CandyMaxWorldRelativeScale / (float)scale;
                        }

                        break;
                    }
            }

            sectorName.textColor = scale < 16 ? foregroundColor :
                scale < 48 ? darkColor : dimColor;
            subsectorNames.textColor = scale < 16 ? foregroundColor :
                scale < 48 ? darkColor : dimColor;

            // Cap pen widths when zooming in
            float penScale = (scale <= 64) ? 1f : (64f / (float)scale);

            float borderPenWidth =
                (scale < MicroBorderMinScale) ? 1 : // When rendering vector borders
                (scale < ParsecMinScale) ? 1 :      // When not rendering "hexes"
                0.16f * penScale; // ... but cut in half by clipping

            float routePenWidth =
                scale <= 16 ? 0.2f :
                0.08f * penScale;

            microBorders.pen.width = borderPenWidth;
            macroBorders.pen.width = borderPenWidth;
            microRoutes.pen.width = routePenWidth;

            amberZone.pen.width = redZone.pen.width = blueZone.pen.width = 0.05f * penScale;

            macroRoutes.pen.width = borderPenWidth;
            macroRoutes.pen.DashStyle = XDashStyle.Dash;

            if (style == Style.Candy)
            {
                subsectorNames.textColor = sectorName.textColor = Color.FromArgb(128, Color.Goldenrod);

                amberZone.pen.width = redZone.pen.width = blueZone.pen.width = 0.035f;

                microRoutes.pen.width = scale < CandyMaxRouteRelativeScale ? routePenWidth : routePenWidth / 2;
                macroBorders.pen.width = scale < CandyMaxBorderRelativeScale ? borderPenWidth : borderPenWidth / 4;
                microBorders.pen.width = scale < CandyMaxBorderRelativeScale ? borderPenWidth : borderPenWidth / 4;
            }

            preferredMimeType = (style == Style.Candy)
                ? System.Net.Mime.MediaTypeNames.Image.Jpeg
                : Util.MediaTypeName_Image_Png;

            pseudoRandomStars.fillColor = foregroundColor;

            macroNames.textColor = foregroundColor;
            macroNames.textHighlightColor = highlightColor;

            macroRoutes.textColor = foregroundColor;
            macroRoutes.textHighlightColor = highlightColor;

            worlds.textColor = foregroundColor;
            worlds.textHighlightColor = highlightColor;

            hexNumber.textColor = lightColor;
            imageBorderColor = lightColor;
        }