Exemplo n.º 1
0
            public override void Process(ResourceManager resourceManager)
            {
                Selector   selector;
                RectangleF tileRect;
                MapOptions options = MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.BordersMajor | MapOptions.BordersMinor | MapOptions.NamesMajor | MapOptions.NamesMinor | MapOptions.WorldsCapitals | MapOptions.WorldsHomeworlds;
                Style      style   = Style.Poster;

                ParseOptions(ref options, ref style);
                string title;
                bool   clipOutsectorBorders;

                if (HasOption("x1") && HasOption("x2") &&
                    HasOption("y1") && HasOption("y2"))
                {
                    // Arbitrary rectangle

                    int x1 = GetIntOption("x1", 0);
                    int x2 = GetIntOption("x2", 0);
                    int y1 = GetIntOption("y1", 0);
                    int y2 = GetIntOption("y2", 0);

                    tileRect = new RectangleF()
                    {
                        X = Math.Min(x1, x2),
                        Y = Math.Min(y1, y2)
                    };
                    tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                    tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                    // NOTE: This (re)initializes a static data structure used for
                    // resolving names into sector locations, so needs to be run
                    // before any other objects (e.g. Worlds) are loaded.
                    SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));
                    selector = new RectSelector(map, resourceManager, tileRect, slop: false);

                    // Include specified hexes
                    tileRect.Offset(-1, -1);
                    tileRect.Width  += 1;
                    tileRect.Height += 1;

                    title = $"Poster ({x1},{y1}) - ({x2},{y2})";
                    clipOutsectorBorders = true;
                }
                else if (HasOption("domain"))
                {
                    string domain = GetStringOption("domain") !;
                    double x, y, w = 2, h = 2;
                    switch (domain.ToLowerInvariant())
                    {
                    case "deneb": x = -4; y = -1; title = "Domain of Deneb"; break;

                    case "vland": x = -2; y = -1; title = "Domain of Vland"; break;

                    case "ilelish": x = -2; y = 1; title = "Domain of Ilelish"; break;

                    case "antares": x = 0; y = -2; title = "Domain of Antares"; break;

                    case "sylea": x = 0; y = 0; title = "Domain of Sylea"; break;

                    case "sol": x = 0; y = 2; title = "Domain of Sol"; break;

                    case "gateway": x = 2; y = 0; title = "Domain of Gateway"; break;

                    // And these aren't domains, but...
                    case "foreven": x = -6; y = -1; title = "Land Grant / Foreven"; break;

                    case "imperium": x = -4; y = -1; w = 7; h = 5; title = "Third Imperium"; break;

                    case "solomani": x = -1.5; y = 2.75; w = 4; h = 2.25; title = "Solomani Confederacy"; break;

                    case "zhodani": x = -8; y = -3; w = 5; h = 3; title = "Zhodani Consulate"; break;

                    case "hive":
                    case "hiver": x = 2; y = 1; w = 6; h = 4; title = "Hive Federation"; break;

                    case "aslan": x = -8; y = 1; w = 7; h = 4; title = "Aslan Hierate"; break;

                    case "vargr": x = -4; y = -4; w = 8; h = 3; title = "Vargr Extents"; break;

                    case "kkree": x = 4; y = -2; w = 4; h = 4; title = "Two Thousand Worlds"; break;

                    case "jp": x = 0; y = -3; w = 4; h = 3; title = "Julian Protectorate"; break;
                    // TODO: Zhodani provinces

                    case "chartedspace": x = -8; y = -3; w = 16; h = 8; title = "Charted Space"; break;

                    case "jg": x = 160; y = 0; w = 2; h = 2; title = "Judges Guild"; break;

                    default:
                        throw new HttpError(404, "Not Found", $"Unknown domain: {domain}");
                    }

                    int x1 = (int)Math.Round(x * Astrometrics.SectorWidth - Astrometrics.ReferenceHex.X + 1);
                    int y1 = (int)Math.Round(y * Astrometrics.SectorHeight - Astrometrics.ReferenceHex.Y + 1);
                    int x2 = (int)Math.Round(x1 + w * Astrometrics.SectorWidth - 1);
                    int y2 = (int)Math.Round(y1 + h * Astrometrics.SectorHeight - 1);

                    tileRect = new RectangleF()
                    {
                        X = Math.Min(x1, x2),
                        Y = Math.Min(y1, y2)
                    };
                    tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                    tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                    // NOTE: This (re)initializes a static data structure used for
                    // resolving names into sector locations, so needs to be run
                    // before any other objects (e.g. Worlds) are loaded.
                    SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));
                    selector = new RectSelector(map, resourceManager, tileRect, slop: false);

                    // Include selected hexes
                    tileRect.Offset(-1, -1);
                    tileRect.Width  += 1;
                    tileRect.Height += 1;

                    // Account for jagged hexes
                    tileRect.Height += 0.5f;
                    tileRect.Inflate(0.25f, 0.10f);
                    if (style == Style.Candy)
                    {
                        tileRect.Width += 0.75f;
                    }

                    clipOutsectorBorders = true;
                }
                else
                {
                    // Sector - either POSTed or specified by name
                    Sector?sector = null;
                    options &= ~MapOptions.SectorGrid;

                    if (Context.Request.HttpMethod == "POST")
                    {
                        bool lint = GetBoolOption("lint", defaultValue: false);
                        Func <ErrorLogger.Record, bool>?filter = null;
                        if (lint)
                        {
                            bool hide_uwp = GetBoolOption("hide-uwp", defaultValue: false);
                            bool hide_tl  = GetBoolOption("hide-tl", defaultValue: false);
                            filter = (ErrorLogger.Record record) =>
                            {
                                if (hide_uwp && record.message.StartsWith("UWP"))
                                {
                                    return(false);
                                }
                                if (hide_tl && record.message.StartsWith("UWP: TL"))
                                {
                                    return(false);
                                }
                                return(true);
                            };
                        }
                        ErrorLogger errors = new ErrorLogger(filter);

                        sector = GetPostedSector(Context.Request, errors) ??
                                 throw new HttpError(400, "Bad Request", "Either file or data must be supplied in the POST data.");
                        if (lint && !errors.Empty)
                        {
                            throw new HttpError(400, "Bad Request", errors.ToString());
                        }


                        title = sector.Names.Count > 0 ? sector.Names[0].Text : "User Data";

                        // TODO: Suppress all OTU rendering.
                        options &= ~(MapOptions.WorldsHomeworlds | MapOptions.WorldsCapitals);
                    }
                    else
                    {
                        string sectorName = GetStringOption("sector") ??
                                            throw new HttpError(400, "Bad Request", "No sector specified.");

                        SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));

                        sector = map.FromName(sectorName) ??
                                 throw new HttpError(404, "Not Found", $"The specified sector '{sectorName}' was not found.");

                        title = sector.Names[0].Text;
                    }

                    if (sector != null && HasOption("subsector") && GetStringOption("subsector") !.Length > 0)
                    {
                        string subsector = GetStringOption("subsector") !;
                        int    index     = sector.SubsectorIndexFor(subsector);
                        if (index == -1)
                        {
                            throw new HttpError(404, "Not Found", $"The specified subsector '{subsector}' was not found.");
                        }

                        selector = new SubsectorSelector(resourceManager, sector, index);

                        tileRect = sector.SubsectorBounds(index);

                        options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid);

                        title = $"{title} - Subsector {'A' + index}";
                    }
Exemplo n.º 2
0
            public override void Process(ResourceManager resourceManager)
            {
                Selector   selector;
                RectangleF tileRect;
                MapOptions options = MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.BordersMajor | MapOptions.BordersMinor | MapOptions.NamesMajor | MapOptions.NamesMinor | MapOptions.WorldsCapitals | MapOptions.WorldsHomeworlds;
                Style      style   = Style.Poster;

                ParseOptions(ref options, ref style);
                string title;
                bool   clipOutsectorBorders;

                if (HasOption("x1") && HasOption("x2") &&
                    HasOption("y1") && HasOption("y2"))
                {
                    // Arbitrary rectangle

                    int x1 = GetIntOption("x1", 0);
                    int x2 = GetIntOption("x2", 0);
                    int y1 = GetIntOption("y1", 0);
                    int y2 = GetIntOption("y2", 0);

                    tileRect = new RectangleF()
                    {
                        X = Math.Min(x1, x2),
                        Y = Math.Min(y1, y2)
                    };
                    tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                    tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                    // NOTE: This (re)initializes a static data structure used for
                    // resolving names into sector locations, so needs to be run
                    // before any other objects (e.g. Worlds) are loaded.
                    SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));
                    selector = new RectSelector(map, resourceManager, tileRect, slop: false);

                    // Include specified hexes
                    tileRect.Offset(-1, -1);
                    tileRect.Width  += 1;
                    tileRect.Height += 1;

                    title = $"Poster ({x1},{y1}) - ({x2},{y2})";
                    clipOutsectorBorders = true;
                }
                else if (HasOption("domain"))
                {
                    string domain = GetStringOption("domain");
                    double x, y, w = 2, h = 2;
                    switch (domain.ToLowerInvariant())
                    {
                    case "deneb": x = -4; y = -1; title = "Domain of Deneb"; break;

                    case "vland": x = -2; y = -1; title = "Domain of Vland"; break;

                    case "ilelish": x = -2; y = 1; title = "Domain of Ilelish"; break;

                    case "antares": x = 0; y = -2; title = "Domain of Antares"; break;

                    case "sylea": x = 0; y = 0; title = "Domain of Sylea"; break;

                    case "sol": x = 0; y = 2; title = "Domain of Sol"; break;

                    case "gateway": x = 2; y = 0; title = "Domain of Gateway"; break;

                    // And these aren't domains, but...
                    case "foreven": x = -6; y = -1; title = "Land Grant / Foreven"; break;

                    case "imperium": x = -4; y = -1; w = 7; h = 5; title = "Third Imperium"; break;

                    case "solomani": x = -1.5; y = 2.75; w = 4; h = 2.25; title = "Solomani Confederacy"; break;

                    case "zhodani": x = -8; y = -3; w = 5; h = 3; title = "Zhodani Consulate"; break;

                    case "hive":
                    case "hiver": x = 2; y = 1; w = 6; h = 4; title = "Hiver Federation"; break;

                    case "aslan": x = -8; y = 1; w = 7; h = 4; title = "Aslan Hierate"; break;

                    case "vargr": x = -4; y = -4; w = 8; h = 3; title = "Vargr Extents"; break;

                    case "kkree": x = 4; y = -2; w = 4; h = 4; title = "Two Thousand Worlds"; break;

                    case "jp": x = 0; y = -3; w = 4; h = 3; title = "Julian Protectorate"; break;
                    // TODO: Zhodani provinces

                    case "chartedspace": x = -8; y = -3; w = 16; h = 8; title = "Charted Space"; break;

                    case "jg": x = 160; y = 0; w = 2; h = 2; title = "Judges Guild"; break;

                    default:
                        throw new HttpError(404, "Not Found", $"Unknown domain: {domain}");
                    }

                    int x1 = (int)Math.Round(x * Astrometrics.SectorWidth - Astrometrics.ReferenceHex.X + 1);
                    int y1 = (int)Math.Round(y * Astrometrics.SectorHeight - Astrometrics.ReferenceHex.Y + 1);
                    int x2 = (int)Math.Round(x1 + w * Astrometrics.SectorWidth - 1);
                    int y2 = (int)Math.Round(y1 + h * Astrometrics.SectorHeight - 1);

                    tileRect = new RectangleF()
                    {
                        X = Math.Min(x1, x2),
                        Y = Math.Min(y1, y2)
                    };
                    tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                    tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                    // NOTE: This (re)initializes a static data structure used for
                    // resolving names into sector locations, so needs to be run
                    // before any other objects (e.g. Worlds) are loaded.
                    SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));
                    selector = new RectSelector(map, resourceManager, tileRect, slop: false);

                    // Include selected hexes
                    tileRect.Offset(-1, -1);
                    tileRect.Width  += 1;
                    tileRect.Height += 1;

                    // Account for jagged hexes
                    tileRect.Height += 0.5f;
                    tileRect.Inflate(0.25f, 0.10f);
                    if (style == Style.Candy)
                    {
                        tileRect.Width += 0.75f;
                    }

                    clipOutsectorBorders = true;
                }
                else
                {
                    // Sector - either POSTed or specified by name
                    Sector sector = null;
                    options &= ~MapOptions.SectorGrid;

                    if (Context.Request.HttpMethod == "POST")
                    {
                        bool lint = GetBoolOption("lint", defaultValue: false);
                        Func <ErrorLogger.Record, bool> filter = null;
                        if (lint)
                        {
                            bool hide_uwp = GetBoolOption("hide-uwp", defaultValue: false);
                            bool hide_tl  = GetBoolOption("hide-tl", defaultValue: false);
                            filter = (ErrorLogger.Record record) =>
                            {
                                if (hide_uwp && record.message.StartsWith("UWP"))
                                {
                                    return(false);
                                }
                                if (hide_tl && record.message.StartsWith("UWP: TL"))
                                {
                                    return(false);
                                }
                                return(true);
                            };
                        }
                        ErrorLogger errors = new ErrorLogger(filter);

                        sector = GetPostedSector(Context.Request, errors) ??
                                 throw new HttpError(400, "Bad Request", "Either file or data must be supplied in the POST data.");
                        if (lint && !errors.Empty)
                        {
                            throw new HttpError(400, "Bad Request", errors.ToString());
                        }


                        title = "User Data";

                        // TODO: Suppress all OTU rendering.
                        options &= ~(MapOptions.WorldsHomeworlds | MapOptions.WorldsCapitals);
                    }
                    else
                    {
                        string sectorName = GetStringOption("sector") ??
                                            throw new HttpError(400, "Bad Request", "No sector specified.");

                        SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));

                        sector = map.FromName(sectorName) ??
                                 throw new HttpError(404, "Not Found", $"The specified sector '{sectorName}' was not found.");

                        title = sector.Names[0].Text;
                    }

                    if (sector != null && HasOption("subsector") && GetStringOption("subsector").Length > 0)
                    {
                        string subsector = GetStringOption("subsector");
                        int    index     = sector.SubsectorIndexFor(subsector);
                        if (index == -1)
                        {
                            throw new HttpError(404, "Not Found", $"The specified subsector '{subsector}' was not found.");
                        }

                        selector = new SubsectorSelector(resourceManager, sector, index);

                        tileRect = sector.SubsectorBounds(index);

                        options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid);

                        title = $"{title} - Subsector {'A' + index}";
                    }
                    else if (sector != null && HasOption("quadrant") && GetStringOption("quadrant").Length > 0)
                    {
                        string quadrant = GetStringOption("quadrant");
                        int    index;
                        switch (quadrant.ToLowerInvariant())
                        {
                        case "alpha": index = 0; quadrant = "Alpha"; break;

                        case "beta": index = 1; quadrant = "Beta"; break;

                        case "gamma": index = 2; quadrant = "Gamma"; break;

                        case "delta": index = 3; quadrant = "Delta"; break;

                        default:
                            throw new HttpError(400, "Bad Request", $"The specified quadrant '{quadrant}' is invalid.");
                        }

                        selector = new QuadrantSelector(resourceManager, sector, index);
                        tileRect = sector.QuadrantBounds(index);

                        options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.SectorsMask);

                        title = $"{title} - {quadrant} Quadrant";
                    }
                    else
                    {
                        selector = new SectorSelector(resourceManager, sector);
                        tileRect = sector.Bounds;

                        options &= ~(MapOptions.SectorGrid);
                    }

                    // Account for jagged hexes
                    tileRect.Height += 0.5f;
                    tileRect.Inflate(0.25f, 0.10f);
                    if (style == Style.Candy)
                    {
                        tileRect.Width += 0.75f;
                    }
                    clipOutsectorBorders = false;
                }

                const double NormalScale = 64; // pixels/parsec - standard subsector-rendering scale
                double       scale       = GetDoubleOption("scale", NormalScale).Clamp(MinScale, MaxScale);

                int  rot   = GetIntOption("rotation", 0) % 4;
                int  hrot  = GetIntOption("hrotation", 0);
                bool thumb = GetBoolOption("thumb", false);

                Stylesheet stylesheet = new Stylesheet(scale, options, style);

                Size tileSize = new Size((int)Math.Floor(tileRect.Width * scale * Astrometrics.ParsecScaleX), (int)Math.Floor(tileRect.Height * scale * Astrometrics.ParsecScaleY));

                if (thumb)
                {
                    tileSize.Width  = (int)Math.Floor(16 * tileSize.Width / scale);
                    tileSize.Height = (int)Math.Floor(16 * tileSize.Height / scale);
                    scale           = 16;
                }

                int            bitmapWidth = tileSize.Width, bitmapHeight = tileSize.Height;
                AbstractMatrix transform = AbstractMatrix.Identity;

                switch (rot)
                {
                case 1:     // 90 degrees clockwise
                    transform.RotatePrepend(90);
                    transform.TranslatePrepend(0, -bitmapHeight);
                    Util.Swap(ref bitmapWidth, ref bitmapHeight);
                    break;

                case 2:     // 180 degrees
                    transform.RotatePrepend(180);
                    transform.TranslatePrepend(-bitmapWidth, -bitmapHeight);
                    break;

                case 3:     // 270 degrees clockwise
                    transform.RotatePrepend(270);
                    transform.TranslatePrepend(-bitmapWidth, 0);
                    Util.Swap(ref bitmapWidth, ref bitmapHeight);
                    break;
                }

                // TODO: Figure out how to compose rot and hrot properly.
                Size bitmapSize = new Size(bitmapWidth, bitmapHeight);

                if (hrot != 0)
                {
                    ApplyHexRotation(hrot, stylesheet, ref bitmapSize, ref transform);
                }

                if (GetBoolOption("clampar", defaultValue: false))
                {
                    // Landscape: 1.91:1 (1.91)
                    // Portrait: 4:5 (0.8)
                    const double MIN_ASPECT_RATIO = 0.8;
                    const double MAX_ASPECT_RATIO = 1.91;
                    double       aspectRatio      = (double)bitmapSize.Width / (double)bitmapSize.Height;
                    Size         newSize          = bitmapSize;
                    if (aspectRatio < MIN_ASPECT_RATIO)
                    {
                        newSize.Width = (int)Math.Floor(bitmapSize.Height * MIN_ASPECT_RATIO);
                    }
                    else if (aspectRatio > MAX_ASPECT_RATIO)
                    {
                        newSize.Height = (int)Math.Floor(bitmapSize.Width / MAX_ASPECT_RATIO);
                    }
                    if (newSize != bitmapSize)
                    {
                        transform.TranslatePrepend(
                            (newSize.Width - bitmapSize.Width) / 2f,
                            (newSize.Height - bitmapSize.Height) / 2f);
                        bitmapSize = newSize;
                    }
                }

                RenderContext ctx = new RenderContext(resourceManager, selector, tileRect, scale, options, stylesheet, tileSize)
                {
                    ClipOutsectorBorders = clipOutsectorBorders
                };

                ProduceResponse(Context, title, ctx, bitmapSize, transform);
            }
Exemplo n.º 3
0
        public override void Process(System.Web.HttpContext context)
        {
            // NOTE: This (re)initializes a static data structure used for
            // resolving names into sector locations, so needs to be run
            // before any other objects (e.g. Worlds) are loaded.
            ResourceManager resourceManager = new ResourceManager(context.Server, context.Cache);

            Selector selector;
            RectangleF tileRect = new RectangleF();
            MapOptions options = MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.BordersMajor | MapOptions.BordersMinor | MapOptions.NamesMajor | MapOptions.NamesMinor | MapOptions.WorldsCapitals | MapOptions.WorldsHomeworlds;
            Stylesheet.Style style = Stylesheet.Style.Poster;
            ParseOptions(context, ref options, ref style);
            string title;
            bool clipOutsectorBorders;

            if (HasOption(context, "x1") && HasOption(context, "x2") &&
                HasOption(context, "y1") && HasOption(context, "y2"))
            {
                // Arbitrary rectangle

                int x1 = GetIntOption(context, "x1", 0);
                int x2 = GetIntOption(context, "x2", 0);
                int y1 = GetIntOption(context, "y1", 0);
                int y2 = GetIntOption(context, "y2", 0);

                tileRect.X = Math.Min(x1, x2);
                tileRect.Y = Math.Min(y1, y2);
                tileRect.Width = Math.Max(x1, x2) - tileRect.X;
                tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);
                selector = new RectSelector(map, resourceManager, tileRect);
                selector.Slop = false;

                tileRect.Offset(-1, -1);
                tileRect.Width += 1;
                tileRect.Height += 1;

                title = String.Format("Poster ({0},{1}) - ({2},{3})", x1, y1, x2, y2);
                clipOutsectorBorders = true;
            }
            else if (HasOption(context, "domain"))
            {
                string domain = GetStringOption(context, "domain");
                int x, y, w = 2, h = 2;
                switch (domain.ToLowerInvariant()) {
                    case "deneb": x = -4; y = -1; title = "Domain of Deneb"; break;
                    case "vland": x = -2; y = -1; title = "Domain of Vland";  break;
                    case "ilelish": x = -2; y = 1; title = "Domain of Ilelish";  break;
                    case "antares": x = 0; y = -2; title = "Domain of Antares";  break;
                    case "sylea": x = 0; y = 0; title = "Domain of Sylea";  break;
                    case "sol": x = 0; y = 2; title = "Domain of Sol";  break;
                    case "gateway": x = 2; y = 0; title = "Domain of Gateway"; break;

                        // And these aren't domains, but...
                    case "foreven": x = -6; y = -1; title = "Land Grab / Foreven"; break;
                    case "imperium": x = -4; y = -1; w = 7; h = 5; title = "Third Imperium"; break;
                    case "solomani": x = -2; y = 2; w = 5; h = 3; title = "Solomani Confederacy"; break;
                    case "zhodani": x = -8; y = -3; w = 5; h = 3; title = "Zhodani Consulate"; break;
                    case "hive":
                    case "hiver": x = 2; y = 1; w = 6; h = 4; title = "Hiver Federation"; break;
                    case "aslan": x = -8; y = 1; w = 7; h = 4; title = "Aslan Hierate"; break;
                    case "vargr": x = -4; y = -4; w = 8; h = 3; title = "Vargr Extents"; break;
                    // TODO: K'kree
                    // TODO: Zhodani provinces

                    case "jg": x = 160; y = 0; w = 2; h = 2; title = "Judges Guild"; break;

                    default:
                        SendError(context.Response, 404, "Not Found", String.Format("Unknown domain: {0}", domain));
                        return;
                }

                int x1 = x * Astrometrics.SectorWidth - Astrometrics.ReferenceHex.X + 1;
                int y1 = y * Astrometrics.SectorHeight - Astrometrics.ReferenceHex.Y + 1;
                int x2 = x1 + w * Astrometrics.SectorWidth - 1;
                int y2 = y1 + h * Astrometrics.SectorHeight - 1;

                tileRect.X = Math.Min(x1, x2);
                tileRect.Y = Math.Min(y1, y2);
                tileRect.Width = Math.Max(x1, x2) - tileRect.X;
                tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);
                selector = new RectSelector(map, resourceManager, tileRect);
                selector.Slop = false;

                tileRect.Offset(-1, -1);
                tileRect.Width += 1;
                tileRect.Height += 1;

                // Account for jagged hexes
                tileRect.Height += 0.5f;
                tileRect.Inflate(0.25f, 0.10f);
                if (style == Stylesheet.Style.Candy)
                    tileRect.Width += 0.75f;

                clipOutsectorBorders = true;
            }
            else
            {
                // Sector - either POSTed or specified by name
                Sector sector = null;
                options = options & ~MapOptions.SectorGrid;

                if (context.Request.HttpMethod == "POST")
                {
                    try
                    {
                        bool lint = GetBoolOption(context, "lint", defaultValue: false);
                        ErrorLogger errors = new ErrorLogger();
                        sector = GetPostedSector(context.Request, errors);
                        if (lint && !errors.Empty)
                        {
                            SendError(context.Response, 400, "Bad Request", errors.ToString());
                        }
                    }
                    catch (Exception ex)
                    {
                        SendError(context.Response, 400, "Bad Request", ex.Message);
                        return;
                    }

                    if (sector == null)
                    {
                        SendError(context.Response, 400, "Bad Request", "Either file or data must be supplied in the POST data.");
                        return;
                    }

                    title = "User Data";

                    // TODO: Suppress all OTU rendering.
                    options = options & ~MapOptions.WorldsHomeworlds & ~MapOptions.WorldsCapitals;
                }
                else
                {
                    string sectorName = GetStringOption(context, "sector");
                    if (sectorName == null)
                    {
                        SendError(context.Response, 400, "Bad Request", "No sector specified.");
                        return;
                    }

                    SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);

                    sector = map.FromName(sectorName);
                    if (sector == null)
                    {
                        SendError(context.Response, 404, "Not Found", String.Format("The specified sector '{0}' was not found.", sectorName));
                        return;
                    }

                    title = sector.Names[0].Text;
                }

                if (sector != null && HasOption(context, "subsector") && GetStringOption(context, "subsector").Length > 0)
                {
                    options = options & ~MapOptions.SubsectorGrid;
                    string subsector = GetStringOption(context, "subsector");
                    int index = sector.SubsectorIndexFor(subsector);
                    if (index == -1)
                    {
                        SendError(context.Response, 404, "Not Found", String.Format("The specified subsector '{0}' was not found.", subsector));
                        return;
                    }

                    selector = new SubsectorSelector(resourceManager, sector, index);

                    tileRect = sector.SubsectorBounds(index);

                    options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid);

                    title = String.Format("{0} - Subsector {1}", title, 'A' + index);
                }
                else if (sector != null && HasOption(context, "quadrant") && GetStringOption(context, "quadrant").Length > 0)
                {
                    string quadrant = GetStringOption(context, "quadrant");
                    int index;
                    switch (quadrant.ToLowerInvariant()) {
                        case "alpha": index = 0; quadrant = "Alpha";  break;
                        case "beta": index = 1; quadrant = "Beta"; break;
                        case "gamma": index = 2; quadrant = "Gamma"; break;
                        case "delta": index = 3; quadrant = "Delta"; break;
                        default:
                            SendError(context.Response, 400, "Bad Request", String.Format("The specified quadrant '{0}' is invalid.", quadrant));
                            return;
                    }

                    selector = new QuadrantSelector(resourceManager, sector, index);
                    tileRect = sector.QuadrantBounds(index);

                    options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.SectorsMask);

                    title = String.Format("{0} - {1} Quadrant", title, quadrant);
                }
                else
                {
                    selector = new SectorSelector(resourceManager, sector);
                    tileRect = sector.Bounds;

                    options &= ~(MapOptions.SectorGrid);
                }

                // Account for jagged hexes
                tileRect.Height += 0.5f;
                tileRect.Inflate(0.25f, 0.10f);
                if (style == Stylesheet.Style.Candy)
                    tileRect.Width += 0.75f;
                clipOutsectorBorders = false;
            }

            const double NormalScale = 64; // pixels/parsec - standard subsector-rendering scale
            double scale = Util.Clamp(GetDoubleOption(context, "scale", NormalScale), MinScale, MaxScale);

            int rot = GetIntOption(context, "rotation", 0) % 4;
            bool thumb = GetBoolOption(context, "thumb", false);

            Stylesheet stylesheet = new Stylesheet(scale, options, style);

            Size tileSize = new Size((int)Math.Floor(tileRect.Width * scale * Astrometrics.ParsecScaleX), (int)Math.Floor(tileRect.Height * scale * Astrometrics.ParsecScaleY));

            if (thumb)
            {
                tileSize.Width = (int)Math.Floor(16 * tileSize.Width / scale);
                tileSize.Height = (int)Math.Floor(16 * tileSize.Height / scale);
                scale = 16;
            }

            int bitmapWidth = tileSize.Width, bitmapHeight = tileSize.Height;
            float translateX = 0, translateY = 0, angle = rot * 90;
            switch (rot)
            {
                case 1: // 90 degrees clockwise
                    Util.Swap(ref bitmapWidth, ref bitmapHeight);
                    translateX = bitmapWidth;
                    break;
                case 2: // 180 degrees
                    translateX = bitmapWidth; translateY = bitmapHeight;
                    break;
                case 3: // 270 degrees clockwise
                    Util.Swap(ref bitmapWidth, ref bitmapHeight);
                    translateY = bitmapHeight;
                    break;
            }

            Render.RenderContext ctx = new Render.RenderContext();
            ctx.resourceManager = resourceManager;
            ctx.selector = selector;
            ctx.tileRect = tileRect;
            ctx.scale = scale;
            ctx.options = options;
            ctx.styles = stylesheet;
            ctx.tileSize = tileSize;
            ctx.clipOutsectorBorders = clipOutsectorBorders;
            ProduceResponse(context, title, ctx, new Size(bitmapWidth, bitmapHeight), rot, translateX, translateY);
        }
Exemplo n.º 4
0
        private void Page_Load(object sender, System.EventArgs e)
        {
            if (!ServiceConfiguration.CheckEnabled("poster", Response))
            {
                return;
            }

            // NOTE: This (re)initializes a static data structure used for
            // resolving names into sector locations, so needs to be run
            // before any other objects (e.g. Worlds) are loaded.
            ResourceManager resourceManager = new ResourceManager(Server, Cache);

            Selector selector;
            RectangleF tileRect = new RectangleF();
            MapOptions options = MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.BordersMajor | MapOptions.BordersMinor | MapOptions.NamesMajor | MapOptions.NamesMinor | MapOptions.WorldsCapitals | MapOptions.WorldsHomeworlds;
            Stylesheet.Style style = Stylesheet.Style.Poster;
            ParseOptions(ref options, ref style);
            string title;

            if (HasOption("x1") && HasOption("x2") &&
                HasOption("y1") && HasOption("y2"))
            {
                // Arbitrary rectangle

                int x1 = GetIntOption("x1", 0);
                int x2 = GetIntOption("x1", 0);
                int y1 = GetIntOption("x1", 0);
                int y2 = GetIntOption("x1", 0);

                tileRect.X = Math.Min(x1, x2);
                tileRect.Y = Math.Min(y1, y2);
                tileRect.Width = Math.Max(x1, x2) - tileRect.X;
                tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);
                selector = new RectSelector(map, resourceManager, tileRect);
                selector.Slop = false;

                tileRect.Offset(-1, -1);
                tileRect.Width += 1;
                tileRect.Height += 1;

                title = String.Format("Poster ({0},{1}) - ({2},{3})", x1, y1, x2, y2);
            }
            else
            {
                // Sector - either POSTed or specified by name
                Sector sector = null;
                options = options & ~MapOptions.SectorGrid;

                if (Request.HttpMethod == "POST")
                {
                    try
                    {
                        sector = GetPostedSector();
                    }
                    catch (Exception ex)
                    {
                        SendError(400, "Invalid request", ex.Message);
                        return;
                    }

                    if (sector == null)
                    {
                        SendError(400, "Invalid request", "Either file or data must be supplied in the POST data.");
                        return;
                    }

                    title = "User Data";
                }
                else
                {
                    string sectorName = GetStringOption("sector");
                    if (sectorName == null)
                    {
                        SendError(404, "Not Found", "No sector specified.");
                        return;
                    }

                    SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);

                    sector = map.FromName(sectorName);
                    if (sector == null)
                    {
                        SendError(404, "Not Found", String.Format("The specified sector '{0}' was not found.", sectorName));
                        return;
                    }

                    title = sector.Names[0].Text;
                }

                if (HasOption("subsector") && GetStringOption("subsector").Length > 0)
                {
                    options = options & ~MapOptions.SubsectorGrid;
                    char ss = GetStringOption("subsector").ToUpperInvariant()[0];
                    if (ss < 'A' || ss > 'P')
                    {
                        SendError(400, "Invalid subsector", String.Format("The subsector index '{0}' is not valid (must be A...P).", ss));
                        return;
                    }

                    int index = (int)(ss) - (int)('A');
                    selector = new SubsectorSelector(resourceManager, sector, index);

                    tileRect = sector.SubsectorBounds(index);

                    options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid);

                    title = String.Format("{0} - Subsector {1}", title, ss);
                }
                else
                {
                    selector = new SectorSelector(resourceManager, sector);
                    tileRect = sector.Bounds;

                    options &= ~(MapOptions.SectorGrid);
                }

                // Account for jagged hexes
                tileRect.X -= 0.25f;
                tileRect.Width += 0.5f;
                tileRect.Height += 0.5f;

                if (style == Stylesheet.Style.Candy)
                {
                    tileRect.Width += 0.75f;
                }

            }

            const double NormalScale = 64; // pixels/parsec - standard subsector-rendering scale
            double scale = Util.Clamp(GetDoubleOption("scale", NormalScale), MinScale, MaxScale);

            int rot = GetIntOption("rotation", 0) % 4;

            Size tileSize = new Size((int)Math.Floor(tileRect.Width * scale * Astrometrics.ParsecScaleX), (int)Math.Floor(tileRect.Height * scale * Astrometrics.ParsecScaleY));

            int bitmapWidth = tileSize.Width, bitmapHeight = tileSize.Height;
            float translateX = 0, translateY = 0, angle = rot * 90;
            switch (rot)
            {
                case 1: // 90 degrees clockwise
                    bitmapWidth = tileSize.Height; bitmapHeight = tileSize.Width;
                    translateX = bitmapWidth;
                    break;
                case 2: // 180 degrees
                    translateX = tileSize.Width; translateY = tileSize.Height;
                    break;
                case 3: // 270 degrees clockwise
                    bitmapWidth = tileSize.Height; bitmapHeight = tileSize.Width;
                    translateY = bitmapHeight;
                    break;
            }

            Render.RenderContext ctx = new Render.RenderContext();
            ctx.resourceManager = resourceManager;
            ctx.selector = selector;
            ctx.tileRect = tileRect;
            ctx.scale = scale;
            ctx.options = options;
            ctx.styles = new Stylesheet(scale, options, style);
            ctx.tileSize = tileSize;
            ProduceResponse(title, ctx, new Size(bitmapWidth, bitmapHeight), rot, translateX, translateY);
        }
Exemplo n.º 5
0
            public override void Process()
            {
                // NOTE: This (re)initializes a static data structure used for
                // resolving names into sector locations, so needs to be run
                // before any other objects (e.g. Worlds) are loaded.
                ResourceManager resourceManager = new ResourceManager(context.Server);

                Selector   selector;
                RectangleF tileRect = new RectangleF();
                MapOptions options  = MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.BordersMajor | MapOptions.BordersMinor | MapOptions.NamesMajor | MapOptions.NamesMinor | MapOptions.WorldsCapitals | MapOptions.WorldsHomeworlds;

                Stylesheet.Style style = Stylesheet.Style.Poster;
                ParseOptions(ref options, ref style);
                string title;
                bool   clipOutsectorBorders;

                if (HasOption("x1") && HasOption("x2") &&
                    HasOption("y1") && HasOption("y2"))
                {
                    // Arbitrary rectangle

                    int x1 = GetIntOption("x1", 0);
                    int x2 = GetIntOption("x2", 0);
                    int y1 = GetIntOption("y1", 0);
                    int y2 = GetIntOption("y2", 0);

                    tileRect.X      = Math.Min(x1, x2);
                    tileRect.Y      = Math.Min(y1, y2);
                    tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                    tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                    SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));
                    selector = new RectSelector(map, resourceManager, tileRect, slop: false);

                    tileRect.Offset(-1, -1);
                    tileRect.Width  += 1;
                    tileRect.Height += 1;

                    title = string.Format("Poster ({0},{1}) - ({2},{3})", x1, y1, x2, y2);
                    clipOutsectorBorders = true;
                }
                else if (HasOption("domain"))
                {
                    string domain = GetStringOption("domain");
                    double x, y, w = 2, h = 2;
                    switch (domain.ToLowerInvariant())
                    {
                    case "deneb": x = -4; y = -1; title = "Domain of Deneb"; break;

                    case "vland": x = -2; y = -1; title = "Domain of Vland"; break;

                    case "ilelish": x = -2; y = 1; title = "Domain of Ilelish"; break;

                    case "antares": x = 0; y = -2; title = "Domain of Antares"; break;

                    case "sylea": x = 0; y = 0; title = "Domain of Sylea"; break;

                    case "sol": x = 0; y = 2; title = "Domain of Sol"; break;

                    case "gateway": x = 2; y = 0; title = "Domain of Gateway"; break;

                    // And these aren't domains, but...
                    case "foreven": x = -6; y = -1; title = "Land Grant / Foreven"; break;

                    case "imperium": x = -4; y = -1; w = 7; h = 5; title = "Third Imperium"; break;

                    case "solomani": x = -1.5; y = 2.75; w = 4; h = 2.25; title = "Solomani Confederacy"; break;

                    case "zhodani": x = -8; y = -3; w = 5; h = 3; title = "Zhodani Consulate"; break;

                    case "hive":
                    case "hiver": x = 2; y = 1; w = 6; h = 4; title = "Hiver Federation"; break;

                    case "aslan": x = -8; y = 1; w = 7; h = 4; title = "Aslan Hierate"; break;

                    case "vargr": x = -4; y = -4; w = 8; h = 3; title = "Vargr Extents"; break;

                    case "kkree": x = 4; y = -2; w = 4; h = 4; title = "Two Thousand Worlds"; break;

                    case "jp": x = 0; y = -3; w = 4; h = 3; title = "Julian Protectorate"; break;
                    // TODO: Zhodani provinces

                    case "chartedspace": x = -8; y = -3; w = 16; h = 8; title = "Charted Space"; break;

                    case "jg": x = 160; y = 0; w = 2; h = 2; title = "Judges Guild"; break;

                    default:
                        throw new HttpError(404, "Not Found", string.Format("Unknown domain: {0}", domain));
                    }

                    int x1 = (int)Math.Round(x * Astrometrics.SectorWidth - Astrometrics.ReferenceHex.X + 1);
                    int y1 = (int)Math.Round(y * Astrometrics.SectorHeight - Astrometrics.ReferenceHex.Y + 1);
                    int x2 = (int)Math.Round(x1 + w * Astrometrics.SectorWidth - 1);
                    int y2 = (int)Math.Round(y1 + h * Astrometrics.SectorHeight - 1);

                    tileRect.X      = Math.Min(x1, x2);
                    tileRect.Y      = Math.Min(y1, y2);
                    tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                    tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                    SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));
                    selector = new RectSelector(map, resourceManager, tileRect, slop: false);

                    tileRect.Offset(-1, -1);
                    tileRect.Width  += 1;
                    tileRect.Height += 1;

                    // Account for jagged hexes
                    tileRect.Height += 0.5f;
                    tileRect.Inflate(0.25f, 0.10f);
                    if (style == Stylesheet.Style.Candy)
                    {
                        tileRect.Width += 0.75f;
                    }

                    clipOutsectorBorders = true;
                }
                else
                {
                    // Sector - either POSTed or specified by name
                    Sector sector = null;
                    options = options & ~MapOptions.SectorGrid;

                    if (context.Request.HttpMethod == "POST")
                    {
                        bool        lint   = GetBoolOption("lint", defaultValue: false);
                        ErrorLogger errors = new ErrorLogger();
                        sector = GetPostedSector(context.Request, errors);
                        if (lint && !errors.Empty)
                        {
                            throw new HttpError(400, "Bad Request", errors.ToString());
                        }

                        if (sector == null)
                        {
                            throw new HttpError(400, "Bad Request", "Either file or data must be supplied in the POST data.");
                        }

                        title = "User Data";

                        // TODO: Suppress all OTU rendering.
                        options = options & ~MapOptions.WorldsHomeworlds & ~MapOptions.WorldsCapitals;
                    }
                    else
                    {
                        string sectorName = GetStringOption("sector");
                        if (sectorName == null)
                        {
                            throw new HttpError(400, "Bad Request", "No sector specified.");
                        }

                        SectorMap.Milieu map = SectorMap.ForMilieu(resourceManager, GetStringOption("milieu"));

                        sector = map.FromName(sectorName);
                        if (sector == null)
                        {
                            throw new HttpError(404, "Not Found", string.Format("The specified sector '{0}' was not found.", sectorName));
                        }

                        title = sector.Names[0].Text;
                    }

                    if (sector != null && HasOption("subsector") && GetStringOption("subsector").Length > 0)
                    {
                        options = options & ~MapOptions.SubsectorGrid;
                        string subsector = GetStringOption("subsector");
                        int    index     = sector.SubsectorIndexFor(subsector);
                        if (index == -1)
                        {
                            throw new HttpError(404, "Not Found", string.Format("The specified subsector '{0}' was not found.", subsector));
                        }

                        selector = new SubsectorSelector(resourceManager, sector, index);

                        tileRect = sector.SubsectorBounds(index);

                        options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid);

                        title = string.Format("{0} - Subsector {1}", title, 'A' + index);
                    }
                    else if (sector != null && HasOption("quadrant") && GetStringOption("quadrant").Length > 0)
                    {
                        string quadrant = GetStringOption("quadrant");
                        int    index;
                        switch (quadrant.ToLowerInvariant())
                        {
                        case "alpha": index = 0; quadrant = "Alpha"; break;

                        case "beta": index = 1; quadrant = "Beta"; break;

                        case "gamma": index = 2; quadrant = "Gamma"; break;

                        case "delta": index = 3; quadrant = "Delta"; break;

                        default:
                            throw new HttpError(400, "Bad Request", string.Format("The specified quadrant '{0}' is invalid.", quadrant));
                        }

                        selector = new QuadrantSelector(resourceManager, sector, index);
                        tileRect = sector.QuadrantBounds(index);

                        options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.SectorsMask);

                        title = string.Format("{0} - {1} Quadrant", title, quadrant);
                    }
                    else
                    {
                        selector = new SectorSelector(resourceManager, sector);
                        tileRect = sector.Bounds;

                        options &= ~(MapOptions.SectorGrid);
                    }

                    // Account for jagged hexes
                    tileRect.Height += 0.5f;
                    tileRect.Inflate(0.25f, 0.10f);
                    if (style == Stylesheet.Style.Candy)
                    {
                        tileRect.Width += 0.75f;
                    }
                    clipOutsectorBorders = false;
                }

                const double NormalScale = 64; // pixels/parsec - standard subsector-rendering scale
                double       scale       = Util.Clamp(GetDoubleOption("scale", NormalScale), MinScale, MaxScale);

                int  rot   = GetIntOption("rotation", 0) % 4;
                bool thumb = GetBoolOption("thumb", false);

                Stylesheet stylesheet = new Stylesheet(scale, options, style);

                Size tileSize = new Size((int)Math.Floor(tileRect.Width * scale * Astrometrics.ParsecScaleX), (int)Math.Floor(tileRect.Height * scale * Astrometrics.ParsecScaleY));

                if (thumb)
                {
                    tileSize.Width  = (int)Math.Floor(16 * tileSize.Width / scale);
                    tileSize.Height = (int)Math.Floor(16 * tileSize.Height / scale);
                    scale           = 16;
                }

                int   bitmapWidth = tileSize.Width, bitmapHeight = tileSize.Height;
                float translateX = 0, translateY = 0;

                switch (rot)
                {
                case 1:     // 90 degrees clockwise
                    Util.Swap(ref bitmapWidth, ref bitmapHeight);
                    translateX = bitmapWidth;
                    break;

                case 2:     // 180 degrees
                    translateX = bitmapWidth; translateY = bitmapHeight;
                    break;

                case 3:     // 270 degrees clockwise
                    Util.Swap(ref bitmapWidth, ref bitmapHeight);
                    translateY = bitmapHeight;
                    break;
                }

                RenderContext ctx = new RenderContext(resourceManager, selector, tileRect, scale, options, stylesheet, tileSize);

                ctx.ClipOutsectorBorders = clipOutsectorBorders;
                ProduceResponse(context, title, ctx, new Size(bitmapWidth, bitmapHeight), rot, translateX, translateY);
            }
Exemplo n.º 6
0
        private void Page_Load(object sender, System.EventArgs e)
        {
            if (!ServiceConfiguration.CheckEnabled("poster", Response))
            {
                return;
            }

            // NOTE: This (re)initializes a static data structure used for
            // resolving names into sector locations, so needs to be run
            // before any other objects (e.g. Worlds) are loaded.
            ResourceManager resourceManager = new ResourceManager(Server, Cache);

            Selector   selector;
            RectangleF tileRect = new RectangleF();
            MapOptions options  = MapOptions.SectorGrid | MapOptions.SubsectorGrid | MapOptions.BordersMajor | MapOptions.BordersMinor | MapOptions.NamesMajor | MapOptions.NamesMinor | MapOptions.WorldsCapitals | MapOptions.WorldsHomeworlds;

            Stylesheet.Style style = Stylesheet.Style.Poster;
            ParseOptions(ref options, ref style);
            string title;

            if (HasOption("x1") && HasOption("x2") &&
                HasOption("y1") && HasOption("y2"))
            {
                // Arbitrary rectangle

                int x1 = GetIntOption("x1", 0);
                int x2 = GetIntOption("x1", 0);
                int y1 = GetIntOption("x1", 0);
                int y2 = GetIntOption("x1", 0);

                tileRect.X      = Math.Min(x1, x2);
                tileRect.Y      = Math.Min(y1, y2);
                tileRect.Width  = Math.Max(x1, x2) - tileRect.X;
                tileRect.Height = Math.Max(y1, y2) - tileRect.Y;

                SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);
                selector      = new RectSelector(map, resourceManager, tileRect);
                selector.Slop = false;

                tileRect.Offset(-1, -1);
                tileRect.Width  += 1;
                tileRect.Height += 1;

                title = String.Format("Poster ({0},{1}) - ({2},{3})", x1, y1, x2, y2);
            }
            else
            {
                // Sector - either POSTed or specified by name
                Sector sector = null;
                options = options & ~MapOptions.SectorGrid;

                if (Request.HttpMethod == "POST")
                {
                    try
                    {
                        sector = GetPostedSector();
                    }
                    catch (Exception ex)
                    {
                        SendError(400, "Invalid request", ex.Message);
                        return;
                    }

                    if (sector == null)
                    {
                        SendError(400, "Invalid request", "Either file or data must be supplied in the POST data.");
                        return;
                    }

                    title = "User Data";
                }
                else
                {
                    string sectorName = GetStringOption("sector");
                    if (sectorName == null)
                    {
                        SendError(404, "Not Found", "No sector specified.");
                        return;
                    }

                    SectorMap map = SectorMap.FromName(SectorMap.DefaultSetting, resourceManager);

                    sector = map.FromName(sectorName);
                    if (sector == null)
                    {
                        SendError(404, "Not Found", String.Format("The specified sector '{0}' was not found.", sectorName));
                        return;
                    }

                    title = sector.Names[0].Text;
                }

                if (HasOption("subsector") && GetStringOption("subsector").Length > 0)
                {
                    options = options & ~MapOptions.SubsectorGrid;
                    char ss = GetStringOption("subsector").ToUpperInvariant()[0];
                    if (ss < 'A' || ss > 'P')
                    {
                        SendError(400, "Invalid subsector", String.Format("The subsector index '{0}' is not valid (must be A...P).", ss));
                        return;
                    }

                    int index = (int)(ss) - (int)('A');
                    selector = new SubsectorSelector(resourceManager, sector, index);

                    tileRect = sector.SubsectorBounds(index);

                    options &= ~(MapOptions.SectorGrid | MapOptions.SubsectorGrid);

                    title = String.Format("{0} - Subsector {1}", title, ss);
                }
                else
                {
                    selector = new SectorSelector(resourceManager, sector);
                    tileRect = sector.Bounds;

                    options &= ~(MapOptions.SectorGrid);
                }

                // Account for jagged hexes
                tileRect.X      -= 0.25f;
                tileRect.Width  += 0.5f;
                tileRect.Height += 0.5f;

                if (style == Stylesheet.Style.Candy)
                {
                    tileRect.Width += 0.75f;
                }
            }

            const double NormalScale = 64; // pixels/parsec - standard subsector-rendering scale
            double       scale       = Util.Clamp(GetDoubleOption("scale", NormalScale), MinScale, MaxScale);

            int rot = GetIntOption("rotation", 0) % 4;

            Size tileSize = new Size((int)Math.Floor(tileRect.Width * scale * Astrometrics.ParsecScaleX), (int)Math.Floor(tileRect.Height * scale * Astrometrics.ParsecScaleY));

            int   bitmapWidth = tileSize.Width, bitmapHeight = tileSize.Height;
            float translateX = 0, translateY = 0, angle = rot * 90;

            switch (rot)
            {
            case 1:     // 90 degrees clockwise
                bitmapWidth = tileSize.Height; bitmapHeight = tileSize.Width;
                translateX  = bitmapWidth;
                break;

            case 2:     // 180 degrees
                translateX = tileSize.Width; translateY = tileSize.Height;
                break;

            case 3:     // 270 degrees clockwise
                bitmapWidth = tileSize.Height; bitmapHeight = tileSize.Width;
                translateY  = bitmapHeight;
                break;
            }

            Render.RenderContext ctx = new Render.RenderContext();
            ctx.resourceManager = resourceManager;
            ctx.selector        = selector;
            ctx.tileRect        = tileRect;
            ctx.scale           = scale;
            ctx.options         = options;
            ctx.styles          = new Stylesheet(scale, options, style);
            ctx.tileSize        = tileSize;
            ProduceResponse(title, ctx, new Size(bitmapWidth, bitmapHeight), rot, translateX, translateY);
        }