Пример #1
0
 private void CheckForTileDuplication(ISuperTile superTile)
 {
     if (this.superTileHistory.ContainsKey(superTile.Scale))
     {
         var offsets = Tuple.Create(superTile.OffsetX, superTile.OffsetY);
         if (this.superTileHistory[superTile.Scale].Contains(offsets))
         {
             var tileDetails = "Scale: {0}, OffsetX: {1}, OffsetY: {2}".Format(
                 superTile.Scale,
                 superTile.OffsetX,
                 superTile.OffsetY);
             throw new ArgumentException(
                       "A duplicate set of supertiles (" + tileDetails + ") has been passed into the tiler - this exception is thrown because it will most likely result int tiles being written over.");
         }
         else
         {
             this.superTileHistory[superTile.Scale].Add(offsets);
         }
     }
     else
     {
         this.superTileHistory.Add(superTile.Scale, new HashSet <Tuple <int, int> >());
     }
 }
Пример #2
0
        /// <summary>
        /// Split one large image (a super tile) into smaller tiles.
        ///     The super tile needs to be aligned within the layer first
        /// NOTE: If a tile spans multiple supertiles,
        /// it will paint forward/backward by using either the end of the current segment and the start
        /// of the next segment or the end of the previous segment and the start of the current segment.
        /// </summary>
        /// <param name="previous">
        /// The previous super tile. Null if nothing beforehand.
        /// </param>
        /// <param name="current">
        /// The super tile currently being operated on.
        /// </param>
        /// <param name="next">
        /// The next super tile that will be processed (positive x-dimension)
        /// </param>
        public virtual void Tile(ISuperTile previous, ISuperTile current, ISuperTile next)
        {
            if (current == null)
            {
                return;
            }

            this.CheckForTileDuplication(current);

            if (!this.WriteImages)
            {
                Log.Debug("Tile method skipped");
                return;
            }

            if (current.Image == null)
            {
                throw new ArgumentException("Image cannot be null");
            }

            Layer layer = this.CalculatedLayers.First(x => Math.Abs(x.XScale - current.Scale) < Epsilon);

            int width   = current.Image.Width,
                height  = current.Image.Height,
                xOffset = current.OffsetX,
                yOffset = current.OffsetY;

            // determine padding needed
            int superTileOffsetInLayerX = this.AlignSuperTileInLayer(
                layer.Width,
                layer.XTiles,
                this.profile.TileWidth,
                current.OffsetX,
                current.Image.Width,
                out var paddingX,
                out var startTileEdgeX);
            int superTileOffsetInLayerY = this.AlignSuperTileInLayer(
                layer.Height,
                layer.YTiles,
                this.profile.TileHeight,
                current.OffsetY,
                current.Image.Height,
                out var paddingY,
                out var startTileEdgeY);

            var deltaTileEdgeSuperTileX = superTileOffsetInLayerX - startTileEdgeX;
            var deltaTileEdgeSuperTileY = superTileOffsetInLayerY - startTileEdgeY;
            var superTileRectangle      = new Rectangle(xOffset, yOffset, width, height);

            if (previous == null && startTileEdgeX % this.profile.TileWidth != 0)
            {
                throw new InvalidOperationException("A non-aligned super tile, with no previous tile has been requested to be drawn, this means a fragment of the supertile will not been drawn.");
            }

            // drawable tiles in the current super tile
            // as a rule only draw the sections that are available in the current tile
            // and as much as we need from the next tile
            double tilesInSuperTileX = CalculateTilesInSuperTile(current.Image.Width, this.profile.TileWidth, paddingX, deltaTileEdgeSuperTileX);
            double tilesInSuperTileY = CalculateTilesInSuperTile(current.Image.Height, this.profile.TileHeight, paddingY, deltaTileEdgeSuperTileY);

            // draw tiles
            for (int i = 0; i < tilesInSuperTileX; i++)
            {
                for (int j = 0; j < tilesInSuperTileY; j++)
                {
                    // clone a segment of the super tile
                    // two cases are catered for bounds that exceed the current super tile
                    // a) Negative X Bias - Paint transparency
                    // b) Positive X Bias - Pull subsection from next image, or paint transparency
                    // Note: best case: Neutral X Bias
                    // Note: no support for anything other than Neutral y Bias

                    // determine how to paint it
                    // supertile relative
                    int layerLeft     = (i * this.profile.TileWidth) + startTileEdgeX,
                        superTileLeft = layerLeft - paddingX;
                    int layerTop      = (j * this.profile.TileHeight) + startTileEdgeY,
                        superTileTop  = layerTop - paddingY;

                    // construct the resulting name of the tile to produced
                    string name = this.profile.GetFileBaseName(
                        this.CalculatedLayers,
                        layer,
                        new Point(layerLeft, layerTop));

                    // make destination image
                    var tileImage = new Image <Rgba32>(
                        this.profile.TileWidth,
                        this.profile.TileHeight);


                    var subsection = new Rectangle
                    {
                        X      = superTileLeft,
                        Y      = superTileTop,
                        Width  = this.profile.TileWidth,
                        Height = this.profile.TileHeight,
                    };
                    ImageComponent[] fragments = GetImageParts(superTileRectangle, subsection);

                    // check if this tiler has already written this tile
                    var renderedBefore = this.tileNameHistory.ContainsKey(name);
                    if (renderedBefore)
                    {
                        // if the exact whole image is being drawn again, throw exception
                        // otherwise continue, do not draw image again
                        if (fragments.Length == 1)
                        {
                            if (fragments[0].XBias != TileBias.Neutral)
                            {
                                throw new InvalidOperationException(
                                          "This program is really not working at all - this should never happen");
                            }

                            throw new DuplicateTileException(name, current);
                        }

                        var holes = this.tileNameHistory[name];
                        if ((holes.Item1 && previous == null) || (holes.Item2 && next == null))
                        {
                            // if the tile was previously rendered with missing fragments
                            // then this is a duplicate
                            throw new DuplicateTileException(name, current);
                        }
                        else
                        {
                            // otherwise, tile should have been fully rendered
                            // skip
                            continue;
                        }
                    }
                    else
                    {
                        // true if it is possible that an adjacent supertile is missing
                        this.tileNameHistory.Add(name, Tuple.Create(previous == null, next == null));
                    }

                    // now paint on destination image
                    // 4 possible sources: nothing (transparent), current, next image (along X-axis), previous image (along x-axis)
                    foreach (ImageComponent imageComponent in fragments)
                    {
                        if (imageComponent.YBias != TileBias.Neutral)
                        {
                            throw new NotImplementedException(
                                      "Currently no support has been implemented for drawing from supertiles that are not aligned with the current tile on the y-axis");
                        }

                        var destinationRect =
                            new Rectangle(
                                new Point(
                                    imageComponent.Fragment.X - superTileLeft,
                                    imageComponent.Fragment.Y - superTileTop),
                                imageComponent.Fragment.Size);

                        var sourceRect =
                            new Rectangle(
                                new Point(
                                    imageComponent.Fragment.Location.X - (superTileOffsetInLayerX - paddingX),
                                    imageComponent.Fragment.Location.Y - (superTileOffsetInLayerY - paddingY)),
                                imageComponent.Fragment.Size);

                        if (imageComponent.XBias == TileBias.Negative)
                        {
                            // two cases here: edge of layer (paint transparent padding)
                            // or grab previous section from image
                            if (previous == null)
                            {
                                // start of stream, paint transparency
                                // default background for the tile is transparent,
                                // no need to paint that again
                            }
                            else
                            {
                                // paint a fraction from the previous image
                                // here, we shift the co-ordinate system one-super-tile's width right
                                sourceRect.X = sourceRect.X + width;
                                tileImage.DrawImage(previous.Image, destinationRect, sourceRect);
                            }
                        }
                        else if (imageComponent.XBias == TileBias.Positive)
                        {
                            // two cases here: edge of layer reached (paint transparent padding)
                            // or grab next section from image
                            if (next == null)
                            {
                                // end of stream, paint transparency
                                // default background for the tile is transparent,
                                // no need to paint that again
                            }
                            else
                            {
                                // paint a fraction from the next image
                                // here, we shift the co-ordinate system one-super-tile's width left
                                sourceRect.X = sourceRect.X - width;
                                tileImage.DrawImage(next.Image, destinationRect, sourceRect);
                            }
                        }
                        else
                        {
                            // neutral
                            tileImage.DrawImage(current.Image, destinationRect, sourceRect);
                        }
                    }


                    // write tile to disk
                    UPath outputTilePath = this.output.Path / (name + "." + MediaTypes.ExtPng);
                    Log.Debug("Saving tile: " + outputTilePath);
                    tileImage.Save(this.output.FileSystem, outputTilePath);
                }
            }
        }
Пример #3
0
        public void TestTileManyGroupsTilesByScaleAndSortsByOffset()
        {
            ISuperTile[] testCases =
            {
                MakeTile(60,     0),
                MakeTile(60,     1),
                MakeTile(30,    16),
                MakeTile(30,  15.5),
                MakeTile(30,    15),
                MakeTile(120,    0),
                MakeTile(1,      0),
            };

            List <ISuperTile> moqCurrent = new List <ISuperTile>(testCases.Length),
                              moqNext    = new List <ISuperTile>(testCases.Length);
            var tilerMock = new Mock <Tiler>(
                this.outputDirectory,
                this.tilingProfile,
                new SortedSet <double>()
            {
                60.0, 24, 12, 6, 2, 1
            },
                60.0,
                1440,
                new SortedSet <double>()
            {
                1, 1, 1, 1, 1, 1
            },
                1.0,
                300);

            tilerMock.Setup(t => t.Tile(It.IsAny <ISuperTile>(), It.IsAny <ISuperTile>(), It.IsAny <ISuperTile>()))
            .Callback <ISuperTile, ISuperTile, ISuperTile>(
                (previous, current, next) =>
            {
                moqCurrent.Add(current);
                moqNext.Add(next);
            });

            tilerMock.Object.TileMany(testCases);

            const ISuperTile empty = null;
            var expected           = new[]
            {
                Tuple.Create(empty, testCases[5]), Tuple.Create(testCases[5], empty),
                Tuple.Create(empty, empty), Tuple.Create(empty, testCases[0]),
                Tuple.Create(testCases[0], testCases[1]), Tuple.Create(testCases[1], empty),
                Tuple.Create(empty, empty), Tuple.Create(empty, testCases[4]),
                Tuple.Create(testCases[4], testCases[3]), Tuple.Create(testCases[3], testCases[2]),
                Tuple.Create(testCases[2], empty), Tuple.Create(empty, empty),
                Tuple.Create(empty, testCases[6]), Tuple.Create(testCases[6], empty),
                Tuple.Create(empty, empty),
            };

            Assert.AreEqual(expected.Length, moqCurrent.Count);

            for (var i = 0; i < expected.Length; i++)
            {
                var expectedArgs = expected[i];

                Assert.AreEqual(expectedArgs.Item1, moqCurrent[i]);
                Assert.AreEqual(expectedArgs.Item2, moqNext[i]);
            }
        }
Пример #4
0
 /// <summary>
 /// Split one large image (a super tile) into smaller tiles
 /// </summary>
 /// <param name="superTile">The super tile to be split</param>
 public virtual void Tile(ISuperTile superTile)
 {
     this.Tile(null, superTile, null);
 }
 public DuplicateTileException(string name, ISuperTile current)
 {
     this.Name = name;
     this.Current = current;
 }