Пример #1
0
        void addPrevSolutionIfSubstantial(Stack <ChunkSolutionRect> solution, ChunkSolutionRect prev)
        {
            if (solution == null)
            {
                throw new ArgumentNullException("solution");
            }

            if (!prev.IsEmpty)
            {
                if (solution.Count == 0)
                {
                    solution.Push(prev);
                }
                else
                {
                    var threshold = this.SubstantialBlock; //SubstantialBlock.RoundMultiply(this.Area.Length);
                    var test      = prev;
                    test.TrimOff(solution.Peek());
                    if (test.Count > threshold)
                    {
                        exclusivePush(solution, prev);
                    }
                }
            }
        }
Пример #2
0
 public bool IsOverlap(ChunkSolutionRect other)
 {
     if (this.Col > other.RightCol || this.RightCol < other.Col || this.Row > other.BottomRow || this.BottomRow < other.Row)
     {
         return(false);
     }
     return(true);
 }
Пример #3
0
        bool tryFullColsOfFalseOnLeft(ref ChunkSolutionRect testsample, int fullcollength)
        {
            var sorter = this.Sorter;
            //full column scan, skim side
            var colsempty = sorter.Columns.TakeWhile(s => !s.Contains(true)).Count();

            if (colsempty != 0)
            {
                testsample.ColWidth  = colsempty;
                testsample.RowHeight = fullcollength;
                return(true);
            }
            return(false);
        }
Пример #4
0
        bool tryFullRowsOfFalseOnTop(ref ChunkSolutionRect testsample, int fullrowlength)
        {
            var sorter = this.Sorter;
            //full row scan, skim top
            var rowsempty = sorter.Rows.TakeWhile(s => !s.Contains(true)).Count();

            if (rowsempty != 0)
            {
                testsample.ColWidth  = fullrowlength;
                testsample.RowHeight = rowsempty;
                return(true);
            }
            return(false);
        }
Пример #5
0
            public void TrimOff(ChunkSolutionRect other)
            {
                if (other.HasAll(this))
                {
                    throw new ArgumentException("The other chunk completely encloses this one.  Trimming off intersections, will leave nothing");
                }

                if (this.IsOverlap(other))
                {
                    //how to do a set subtraction, based simply on x,y,w,h of 2 rect...
                    //simply just find which edge intersects with this rectangle and "chop" off in direction of inside the rectangle
                    //var clearright = this.RightCol < other.Col;
                    //var clearbottom = this.BottomRow < other.Row;
                    //var cleartop = this.Row > other.BottomRow;
                    //var clearleft = this.Col > other.RightCol;

                    var topinside    = this.Row < other.Row && other.Row <= this.BottomRow;
                    var bottominside = this.Row <= other.BottomRow && other.BottomRow < this.BottomRow;
                    var leftinside   = this.Col < other.Col && other.Col <= this.RightCol;
                    var rightinside  = this.Col <= other.RightCol && other.RightCol < this.RightCol;

                    if (leftinside) //left edge of other is inside right border, so erase everything of this, right of other's border
                    {
                        this.ColWidth = this.Col - other.Col - 1;
                    }
                    if (topinside)//top edge of other is inside bottom border, so erase everything of this, bottom of other's border
                    {
                        this.RowHeight = this.Row - other.Row - 1;
                    }
                    if (rightinside)
                    {
                        var right = this.RightCol;
                        this.ColWidth = this.RightCol - other.RightCol;
                        this.Col      = other.RightCol + 1; // other.Col - this.ColWidth - 1;
                        System.Diagnostics.Debug.Assert(this.ColWidth > 0, "this is obvious, the width still has to be >0");
                        System.Diagnostics.Debug.Assert(right == this.RightCol, "these should still be the same");
                        System.Diagnostics.Debug.Assert(other.RightCol < this.Col, "the current left edge should be distinct from other's right");
                    }
                    if (bottominside)
                    {
                        var bottom = this.BottomRow;
                        this.RowHeight = this.BottomRow - other.BottomRow;
                        this.Row       = other.BottomRow + 1;
                        System.Diagnostics.Debug.Assert(this.RowHeight > 0, "this is obvious, the height still has to be >0");
                        System.Diagnostics.Debug.Assert(bottom == this.BottomRow, "these should still be the same");
                        System.Diagnostics.Debug.Assert(other.BottomRow < this.Row, "the current top edge should be distinct from other's bottom");
                    }
                }
            }
Пример #6
0
 void exclusivePush(Stack <ChunkSolutionRect> solution, ChunkSolutionRect entry)
 {
     if (!entry.IsEmpty)
     {
         if (solution.Count == 0)
         {
             solution.Push(entry);
         }
         else
         {
             var last = solution.Pop();
             last.TrimOff(entry); // the popped off one, AND remove common records from new set
             entry.TrimOff(last); // now remove the common records from older one set, from latest set, to make them mutually exclusive
             solution.Push(last);
             solution.Push(entry);
         }
     }
 }
Пример #7
0
 public int SubstantialBlock = 75; //100
 bool ifSubstantial(ChunkSolutionRect current, ChunkSolutionRect prev)
 {
     if (!current.IsEmpty)
     {
         var threshold = this.SubstantialBlock; //SubstantialBlock.RoundMultiply(this.Area.Length);
         var test      = prev;
         test.TrimOff(prev);
         if (test.Count > threshold)
         {
             return(true);
         }
         else
         {
             return(false);
         }
     }
     else
     {
         throw new ArgumentException("The current solution is empty, how is this a solution, much less a substantial one compared to previous");
     }
 }
Пример #8
0
        IEnumerable <ChunkSolutionRect> scanColendingForSolutions(int startrow, int[] colend, int colcount, ChunkSolutionRect lastsolution, int rowcount)
        {
            var sorter = this.Sorter;

            Stack <ChunkSolutionRect> solutions = new Stack <ChunkSolutionRect>();
            var testsample = new ChunkSolutionRect()
            {
                Col = 0, Row = startrow
            };
            var maxcount      = 0;
            var bottomedgerow = int.MaxValue;
            var samplemax     = default(ChunkSolutionRect);

            //skim the side, search for solutions in bottom bubble
            int compensate         = 0; //the column heights were searched for before solutions were found.  Now a place to store new column heights, if they were to be searched for now
            var lastsolutionbottom = lastsolution.BottomRow + 1;

            if (lastsolutionbottom > startrow)
            {
                compensate = lastsolutionbottom - startrow; //we just store the difference between the last solution row, and the where search started
            }
            if (startrow + compensate < rowcount)
            {
                testsample.Col = 0;
                testsample.Row = startrow + compensate; //obvious the solution has to start, forward compensated for the new solution start
                for (int i = 0; i < colcount; i++)
                {
                    var rowheight = colend[i] - compensate; //and the height has to be backward compensated for new solution start
                    if (rowheight <= 0)                     //backward compensation makes negative possible
                    {
                        break;
                    }
                    if (rowheight < bottomedgerow)
                    {
                        bottomedgerow = rowheight;
                    }
                    else if (rowheight > bottomedgerow)
                    {
                        rowheight = bottomedgerow;
                    }
                    testsample.ColWidth  = i + 1;
                    testsample.RowHeight = rowheight;
                    var count = testsample.Count; //(i - startcol) * (j - startrow + 1);
                    if (count > maxcount)
                    {
                        maxcount = count;
                        if (samplemax.RowHeight != testsample.RowHeight) //don't bother doing the comprehensive test, if it doesn't pass this simple one b/c unless the height of sample changes, the testsample will always be superset of prev samplemax
                        {
                            addPrevSolutionIfSubstantial(solutions, samplemax);
                        }
                        samplemax = testsample;
                        System.Diagnostics.Debug.WriteLine("max at each (row {0}) x (col {1}) = (count elements {2}) <= running max={3}, min right edge={4}", rowheight, i + 1, count, maxcount, bottomedgerow);
#if DEBUG
                        for (int y = testsample.Row; y <= testsample.BottomRow; y++)
                        {
                            for (int x = testsample.Col; x <= testsample.RightCol; x++)
                            {
                                if (sorter[y, x])
                                {
                                    System.Diagnostics.Debug.WriteLine(sorter[y, x], "Solution is misaligned.  THe solution elements should all be false");
                                }
                            }
                        }
#endif
                    }
                }

                if (solutions.Count == 0 || samplemax != solutions.Peek())
                {
                    exclusivePush(solutions, samplemax);
                }
            }
            return(solutions);
        }
Пример #9
0
        IEnumerable <ChunkSolutionRect> scanRowendingForSolutions(int startcol, int[] rowend, int rowcount)
        {
            var sorter = this.Sorter;

            Stack <ChunkSolutionRect> solutions = new Stack <ChunkSolutionRect>();
            var testsample = new ChunkSolutionRect()
            {
                Col = startcol, Row = 0
            };
            var maxcount     = 0;
            var rightedgecol = int.MaxValue;
            var samplemax    = default(ChunkSolutionRect);

            for (int j = 0; j < rowcount; j++)
            {
                var colwidth = rowend[j]; // the rowend is actually a column index, or length to first true, or end of elements
                if (colwidth == 0)
                {
                    break;
                }
                if (colwidth < rightedgecol)
                {
                    rightedgecol = colwidth;
                }
                else if (colwidth > rightedgecol)
                {
                    colwidth = rightedgecol;
                }
                testsample.ColWidth  = colwidth;
                testsample.RowHeight = j + 1;
                var count = testsample.Count; //(i - startcol) * (j - startrow + 1);
                if (count > maxcount)
                {
                    maxcount = count;
                    if (samplemax.ColWidth != testsample.ColWidth) //don't bother doing the comprehensive test, if it doesn't pass this simple one b/c unless the width of sample changes, the testsample will always be superset of prev samplemax
                    {
                        addPrevSolutionIfSubstantial(solutions, samplemax);
                    }
                    samplemax = testsample;
                    System.Diagnostics.Debug.WriteLine("max at each (row {0}) x (col {1}) = (count elements {2}) <= running max={3}, min right edge={4}", j + 1, colwidth, count, maxcount, rightedgecol);
#if DEBUG
                    for (int y = testsample.Row; y <= testsample.BottomRow; y++)
                    {
                        for (int x = testsample.Col; x <= testsample.RightCol; x++)
                        {
                            if (sorter[y, x])
                            {
                                System.Diagnostics.Debug.WriteLine(sorter[y, x], "Solution is misaligned.  THe solution elements should all be false");
                            }
                        }
                    }
#endif
                }
            }

            if (solutions.Count == 0 || samplemax != solutions.Peek())
            {
                exclusivePush(solutions, samplemax);
            }

            return(solutions);
        }
Пример #10
0
        public IEnumerable <ArraySubblock> Chunkify(bool heavy)
        {
            if (this.Area == null)
            {
                this.Area = this.Sorter.Area;
            }
            var area   = this.Area;
            var sorter = this.Sorter;

            while (true)
            {
                sorter.Sort();
                if (sorter.IsAllEqual && sorter.IsAllTrue)
                {
                    break;
                }

                //initialize program variables
                ChunkSolutionRect testsample = new ChunkSolutionRect()
                {
                    Row = 0, Col = 0
                };
                var rowcount = sorter.RowCount;
                var colcount = sorter.ColumnCount;

                if (!sorter[0, 0])
                {
                    //full row scan, skim top
                    if (tryFullRowsOfFalseOnTop(ref testsample, colcount))
                    {
                        yield return(testsample.ToArraySubblock(sorter));
                    }
                    //full column scan, skim side
                    else if (tryFullColsOfFalseOnLeft(ref testsample, rowcount))
                    {
                        yield return(testsample.ToArraySubblock(sorter));
                    }
                    else
                    {
                        //look for biggest block
                        testsample = getBiggestPossibleRectInUpperLeft(rowcount, colcount);
                        yield return(testsample.ToArraySubblock(sorter));
                    }
                }
                else //sorter[0, 0] is true
                {
                    //algorithm below, will actually work for sorter[0, 0] is false, but the above algorithm is much easier to understand

                    //skim the top irregular shapes, bubbles in upper left
                    //Stack<ChunkSolutionRect> solutions = new Stack<ChunkSolutionRect>();
                    //ChunkSolutionRect samplemax = default(ChunkSolutionRect);
                    //var max = 0;

                    //find first bubbles in top and left, set to startcol, startrow
                    var startcol = getFirstFalseOnTopRow(colcount);
                    var startrow = getFirstFalseOnLeftCol(rowcount);

                    //run in parallel search for the first row or col with true
                    int[] rowlen = null, collen = null;
                    Parallel.For(0, 2, delegate(int branch)
                    {
                        if (branch == 1)
                        {
                            rowlen = getArrayOfFirstTrueInAllRowAfterCol(startcol, colcount, rowcount);
                        }
                        else
                        {
                            collen = getArrayOfFirstTrueInAllColumnAfterRow(startrow, colcount, rowcount);
                        }
                    });

                    //search for solutions in top bubble
                    var lastsolution = default(ChunkSolutionRect);
                    foreach (var solution in scanRowendingForSolutions(startcol, rowlen, rowcount).Reverse())
                    {
                        lastsolution = solution;
                        yield return(solution.ToArraySubblock(sorter));
                    }

                    foreach (var solution in scanColendingForSolutions(startrow, collen, colcount, lastsolution, rowcount).Reverse())
                    {
                        lastsolution = solution;
                        yield return(solution.ToArraySubblock(sorter));
                    }

                    //foreach (var solution in solutions.Reverse())
                    //    yield return solution.ToArraySubblock(sorter);
                }
            }
        }
Пример #11
0
 public bool HasAll(ChunkSolutionRect other)
 {
     return(other.Exists(this.Row, this.Col) && other.Exists(this.Row, this.RightCol) && other.Exists(this.BottomRow, this.Col) && other.Exists(this.BottomRow, this.RightCol));
 }