Splits a parent rectangle into "bin" rectangles.
A bin is a small square that fits into a parent rectangle. This class splits the parent into consecutive bins, running from left to right along the bottom of the parent and then moving up a row.

Pass the parent rectangle to the constructor, along with the length of the bin. Call TryGetNextBin to get the next bin, and call to get any space not occupied by the returned bins.

Inheritance: Object
    Test1()
    {
        // 2 rows of 3 bins each, space left over at top.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            new Rectangle( new Point(1, 1), new Size(6, 5) ),
            2);

        Rectangle oReturnedBin;

        foreach (Rectangle oExpectedBin in new Rectangle[] {

            new Rectangle( new Point(1, 4), new Size(2, 2) ),
            new Rectangle( new Point(3, 4), new Size(2, 2) ),
            new Rectangle( new Point(5, 4), new Size(2, 2) ),

            new Rectangle( new Point(1, 2), new Size(2, 2) ),
            new Rectangle( new Point(3, 2), new Size(2, 2) ),
            new Rectangle( new Point(5, 2), new Size(2, 2) ),
            } )
        {
            Assert.IsTrue( oRectangleBinner.TryGetNextBin(out oReturnedBin) );
            Assert.AreEqual(oExpectedBin, oReturnedBin);
        }

        Assert.IsFalse( oRectangleBinner.TryGetNextBin(out oReturnedBin) );
        Assert.IsFalse( oRectangleBinner.TryGetNextBin(out oReturnedBin) );

        Rectangle oRemainingRectangle;

        Assert.IsTrue( oRectangleBinner.TryGetRemainingRectangle(
            out oRemainingRectangle) );

        Assert.AreEqual(new Rectangle( new Point(1, 1), new Size(6, 1) ),
            oRemainingRectangle);
    }
    LayOutSmallerComponentsInBins
    (
        IGraph graph,
        ICollection<IVertex> verticesToLayOut,
        LayoutContext layoutContext,
        out ICollection<IVertex> remainingVertices,
        out Rectangle remainingRectangle
    )
    {
        AssertValid();

        remainingVertices = null;
        remainingRectangle = Rectangle.Empty;

        // This method modifies some of the graph's metadata.  Save the
        // original metadata.

        Boolean bOriginalGraphHasBeenLaidOut =
            LayoutMetadataUtil.GraphHasBeenLaidOut(graph);

        ICollection<IVertex> oOriginalLayOutTheseVerticesOnly =
            ( ICollection<IVertex> )graph.GetValue(
                ReservedMetadataKeys.LayOutTheseVerticesOnly,
                typeof( ICollection<IVertex> ) );

        // Split the vertices into strongly connected components, sorted in
        // increasing order of vertex count.

        ConnectedComponentCalculator oConnectedComponentCalculator =
            new ConnectedComponentCalculator();

        IList< LinkedList<IVertex> > oComponents =
            oConnectedComponentCalculator.CalculateStronglyConnectedComponents(
                verticesToLayOut, graph, true);

        Int32 iComponents = oComponents.Count;

        // This object will split the graph rectangle into bin rectangles.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            layoutContext.GraphRectangle, m_iBinLength);

        Int32 iComponent = 0;

        for (iComponent = 0; iComponent < iComponents; iComponent++)
        {
            LinkedList<IVertex> oComponent = oComponents[iComponent];
            Int32 iVerticesInComponent = oComponent.Count;

            if (iVerticesInComponent> m_iMaximumVerticesPerBin)
            {
                // The vertices in the remaining components should not be
                // binned.

                break;
            }

            Rectangle oBinRectangle;

            if ( !oRectangleBinner.TryGetNextBin(out oBinRectangle) )
            {
                // There is no room for an additional bin rectangle.

                break;
            }

            // Lay out the component within the bin rectangle.

            LayOutComponentInBin(graph, oComponent, oBinRectangle);
        }

        // Restore the original metadata on the graph.

        if (bOriginalGraphHasBeenLaidOut)
        {
            LayoutMetadataUtil.MarkGraphAsLaidOut(graph);
        }
        else
        {
            LayoutMetadataUtil.MarkGraphAsNotLaidOut(graph);
        }

        if (oOriginalLayOutTheseVerticesOnly != null)
        {
            graph.SetValue(ReservedMetadataKeys.LayOutTheseVerticesOnly,
                oOriginalLayOutTheseVerticesOnly);
        }
        else
        {
            graph.RemoveKey(ReservedMetadataKeys.LayOutTheseVerticesOnly);
        }

        if ( oRectangleBinner.TryGetRemainingRectangle(
            out remainingRectangle) )
        {
            remainingVertices = GetRemainingVertices(oComponents, iComponent);

            return (remainingVertices.Count > 0);
        }

        return (false);
    }
    Test11()
    {
        // Weird case: 2 rows of 3 bins each, no space left over at top, top
        // row only partially filled.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            new Rectangle( new Point(1, 2), new Size(6, 4) ),
            2);

        Rectangle oReturnedBin;

        foreach (Rectangle oExpectedBin in new Rectangle[] {

            new Rectangle( new Point(1, 4), new Size(2, 2) ),
            new Rectangle( new Point(3, 4), new Size(2, 2) ),
            new Rectangle( new Point(5, 4), new Size(2, 2) ),

            new Rectangle( new Point(1, 2), new Size(2, 2) ),
            new Rectangle( new Point(3, 2), new Size(2, 2) ),
            } )
        {
            Assert.IsTrue( oRectangleBinner.TryGetNextBin(out oReturnedBin) );
            Assert.AreEqual(oExpectedBin, oReturnedBin);
        }

        Rectangle oRemainingRectangle;

        Assert.IsTrue( oRectangleBinner.TryGetRemainingRectangle(
            out oRemainingRectangle) );

        Assert.AreEqual(new Rectangle( new Point(5, 2), new Size(2, 2) ),
            oRemainingRectangle);
    }
    Test9()
    {
        // 2 rows of 3 bins each, space left over at top, but only 1 bin asked
        // for.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            new Rectangle( new Point(1, 1), new Size(6, 5) ),
            2);

        Rectangle oReturnedBin;

        foreach (Rectangle oExpectedBin in new Rectangle[] {

            new Rectangle( new Point(1, 4), new Size(2, 2) ),
            } )
        {
            Assert.IsTrue( oRectangleBinner.TryGetNextBin(out oReturnedBin) );
            Assert.AreEqual(oExpectedBin, oReturnedBin);
        }

        Rectangle oRemainingRectangle;

        Assert.IsTrue( oRectangleBinner.TryGetRemainingRectangle(
            out oRemainingRectangle) );

        Assert.AreEqual(new Rectangle( new Point(1, 1), new Size(6, 3) ),
            oRemainingRectangle);
    }
    Test6()
    {
        // TryGetNextBin() never called.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            new Rectangle( new Point(1, 1), new Size(6, 5) ),
            2);

        Rectangle oRemainingRectangle;

        Assert.IsTrue( oRectangleBinner.TryGetRemainingRectangle(
            out oRemainingRectangle) );

        Assert.AreEqual(new Rectangle( new Point(1, 1), new Size(6, 5) ),
            oRemainingRectangle);
    }
    Test5()
    {
        // Too small for even one bin.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            new Rectangle( new Point(10, 20), new Size(5, 5) ),
            6);

        Rectangle oReturnedBin;

        Assert.IsFalse( oRectangleBinner.TryGetNextBin(out oReturnedBin) );

        Rectangle oRemainingRectangle;

        Assert.IsTrue( oRectangleBinner.TryGetRemainingRectangle(
            out oRemainingRectangle) );

        Assert.AreEqual(new Rectangle( new Point(10, 20), new Size(5, 5) ),
            oRemainingRectangle);
    }
    Test4()
    {
        // Room for exactly one bin.

        RectangleBinner oRectangleBinner = new RectangleBinner(
            new Rectangle( new Point(10, 20), new Size(10, 10) ),
            10);

        Rectangle oReturnedBin;

        foreach (Rectangle oExpectedBin in new Rectangle[] {

            new Rectangle( new Point(10, 20), new Size(10, 10) ),
            } )
        {
            Assert.IsTrue( oRectangleBinner.TryGetNextBin(out oReturnedBin) );
            Assert.AreEqual(oExpectedBin, oReturnedBin);
        }

        Assert.IsFalse( oRectangleBinner.TryGetNextBin(out oReturnedBin) );

        Rectangle oRemainingRectangle;

        Assert.IsFalse( oRectangleBinner.TryGetRemainingRectangle(
            out oRemainingRectangle) );
    }
Example #8
0
        LayOutSmallerComponentsInBins
        (
            IGraph graph,
            ICollection <IVertex> verticesToLayOut,
            LayoutContext layoutContext,
            out ICollection <IVertex> remainingVertices,
            out Rectangle remainingRectangle
        )
        {
            AssertValid();

            remainingVertices  = null;
            remainingRectangle = Rectangle.Empty;

            // This method modifies some of the graph's metadata.  Save the
            // original metadata.

            Boolean bOriginalGraphHasBeenLaidOut =
                LayoutMetadataUtil.GraphHasBeenLaidOut(graph);

            ICollection <IVertex> oOriginalLayOutTheseVerticesOnly =
                (ICollection <IVertex>)graph.GetValue(
                    ReservedMetadataKeys.LayOutTheseVerticesOnly,
                    typeof(ICollection <IVertex>));

            // Split the vertices into strongly connected components, sorted in
            // increasing order of vertex count.

            ConnectedComponentCalculator oConnectedComponentCalculator =
                new ConnectedComponentCalculator();

            IList <LinkedList <IVertex> > oComponents =
                oConnectedComponentCalculator.CalculateStronglyConnectedComponents(
                    verticesToLayOut, graph, true);

            Int32 iComponents = oComponents.Count;

            // This object will split the graph rectangle into bin rectangles.

            RectangleBinner oRectangleBinner = new RectangleBinner(
                layoutContext.GraphRectangle, m_iBinLength);

            Int32 iComponent = 0;

            for (iComponent = 0; iComponent < iComponents; iComponent++)
            {
                LinkedList <IVertex> oComponent = oComponents[iComponent];
                Int32 iVerticesInComponent      = oComponent.Count;

                if (iVerticesInComponent > m_iMaximumVerticesPerBin)
                {
                    // The vertices in the remaining components should not be
                    // binned.

                    break;
                }

                Rectangle oBinRectangle;

                if (!oRectangleBinner.TryGetNextBin(out oBinRectangle))
                {
                    // There is no room for an additional bin rectangle.

                    break;
                }

                // Lay out the component within the bin rectangle.

                LayOutComponentInBin(graph, oComponent, oBinRectangle);
            }

            // Restore the original metadata on the graph.

            if (bOriginalGraphHasBeenLaidOut)
            {
                LayoutMetadataUtil.MarkGraphAsLaidOut(graph);
            }
            else
            {
                LayoutMetadataUtil.MarkGraphAsNotLaidOut(graph);
            }

            if (oOriginalLayOutTheseVerticesOnly != null)
            {
                graph.SetValue(ReservedMetadataKeys.LayOutTheseVerticesOnly,
                               oOriginalLayOutTheseVerticesOnly);
            }
            else
            {
                graph.RemoveKey(ReservedMetadataKeys.LayOutTheseVerticesOnly);
            }

            if (oRectangleBinner.TryGetRemainingRectangle(
                    out remainingRectangle))
            {
                remainingVertices = GetRemainingVertices(oComponents, iComponent);

                return(remainingVertices.Count > 0);
            }

            return(false);
        }