Overlap detection for laying out elements on a page

How would you simplify/improve the readability of this code? Because even after my attempt to improve the readability I think it still looks messy.

    private bool INTOP = false;
    private bool INLEFT = false;
    private bool INRIGHT = false;
    private bool INBOTTOM = false;

    private bool BEYOND = false;

    private List<DependencyObject> BEYONDDO = new List<DependencyObject>();
    private List<DependencyObject> FULLOUT = new List<DependencyObject>();

    private List<DependencyObject> TOPLEFTDO = new List<DependencyObject>();
    private List<DependencyObject> TOPDO = new List<DependencyObject>();
    private List<DependencyObject> TOPRIGHTDO = new List<DependencyObject>();

    private List<DependencyObject> LEFTDO = new List<DependencyObject>();
    private List<DependencyObject> CURRENTPAGEDO = new List<DependencyObject>();
    private List<DependencyObject> RIGHTDO = new List<DependencyObject>();

    private List<DependencyObject> BOTTOMLEFTDO = new List<DependencyObject>();
    private List<DependencyObject> BOTTOMDO = new List<DependencyObject>();
    private List<DependencyObject> BOTTOMRIGHTDO = new List<DependencyObject>();

    private bool ForeachChildIn(DependencyObject myPage, IList<DependencyObject> childList)
    {
        var result = false;
        foreach (var item in childList)
        {
            var itemresult = false;
            if (item is Visual && myPage is Visual)
            {
                var myVisual = item as Visual;

                //relative Position des myVisual zu VisualElement
                Point relativeSartPoint = myVisual.TransformToAncestor((Visual)myPage)
                                                  .Transform(new Point(0, 0));
                var aw = (double)myVisual.GetValue(FrameworkElement.ActualWidthProperty);
                var ah = (double)myVisual.GetValue(FrameworkElement.ActualHeightProperty);
                var relativeEndHorizontal = relativeSartPoint.X + aw;
                var relativeEndVertikal = relativeSartPoint.Y + ah;

                Point relativeEndPoint = new Point(relativeEndHorizontal, relativeEndVertikal);

                INTOP = (PageRect.Top <= relativeSartPoint.Y);
                INBOTTOM = (PageRect.Bottom >= relativeEndPoint.Y);

                INLEFT = (PageRect.Left <= relativeSartPoint.X);
                INRIGHT = (PageRect.Right >= relativeEndPoint.X);

                BEYOND = (PageRect.Top >= relativeEndPoint.Y)
                      || (PageRect.Bottom <= relativeSartPoint.Y)
                      || (PageRect.Left >= relativeEndPoint.X)
                      || (PageRect.Right <= relativeSartPoint.X);

                if (IsIN())
                {
                    result = true;
                    itemresult = true;
                }
                else if (BEYOND)
                    BEYONDDO.Add(item);
                else if (((relativeSartPoint.X == 0 && relativeSartPoint.Y == 0) || (IsTopOverlap()) && IsLeftOverlap()) && IsRightOverlap() && IsBottomOverlap())
                    FULLOUT.Add(item);
                else if (IsTopOverlap() && IsLeftOverlap())
                    TOPLEFTDO.Add(item);
                else if (IsTopOverlap() && IsRightOverlap())
                    TOPRIGHTDO.Add(item);
                else if (IsTopOverlap())
                    TOPDO.Add(item);
                else if (IsBottomOverlap() && IsLeftOverlap())
                    BOTTOMLEFTDO.Add(item);
                else if (IsBottomOverlap() && IsRightOverlap())
                    BOTTOMRIGHTDO.Add(item);
                else if (IsBottomOverlap())
                    BOTTOMDO.Add(item);
                else if (IsRightOverlap())
                    RIGHTDO.Add(item);
                else if (IsLeftOverlap())
                    LEFTDO.Add(item);
            }
            if (!itemresult)
                if (ForeachChildIn(item, item.getChilds().ToList()))
                    result = true;
                else if ((Visibility)item.GetValue(FrameworkElement.VisibilityProperty) == Visibility.Visible)
                    //item.SetValue(FrameworkElement.VisibilityProperty, Visibility.Hidden);
                    //this part is just for testing
                    if (item is Control)
                        ((Control)item).Background = Brushes.LimeGreen;
                    else if (item is Panel)
                        ((Panel)item).Background = Brushes.LimeGreen;
        }
        return result;
    }

My attempt to improve readability by encapsulating conditions in meaningful methods:

private bool IsIN()
{
    return INTOP && INLEFT && INRIGHT && INBOTTOM;
}

private bool IsTopOverlap()
{
    return !BEYOND && !INTOP;
}

private bool IsLeftOverlap()
{
    return !BEYOND && !INLEFT;
}

private bool IsRightOverlap()
{
    return !BEYOND && !INRIGHT;
}

private bool IsBottomOverlap()
{
    return !BEYOND && !INBOTTOM;
}

Disclaimer

This code isn’t in production it is just for testing purposes.


To answer the question about what and how many combinations are possible here are all possible combination to make it a bit more visual think about a Numpad:

Numpad

We have 9 basic positions.

Number 5 represents IsIN(). Number 1, 2, 3, 4, 6, 7, 8, 9 are represented by BEYOND. After these basic positions we come to the overlapping if a DO covers Number 5 (partly or full) +

7,8,9 it is represented by IsTopOverlap()

or

1,4,7 it is represented by IsLeftOverlap()

or

9,6,3 it is represented by IsRightOverlap()

or

1,2,3 it is represented by IsBottomOverlap()

Now we get nearly all possible combinations because we can check for intersections on the corners, but there could DO which covers more than that they are represented by

((relativeSartPoint.X == 0 && relativeSartPoint.Y == 0) || (IsTopOverlap()) && IsLeftOverlap()) && IsRightOverlap() && IsBottomOverlap()

If some of you is interested in what the current code looks like
here a link to SO Creating an Intelligent DocumentPaginator …

Answer

Please, pretty please, use braces. They are totally lacking in your code.

if (!itemresult)
   if (ForeachChildIn(item, item.getChilds().ToList()))
       result = true;
   else if ((Visibility)item.GetValue(FrameworkElement.VisibilityProperty) == Visibility.Visible)
        if (item is Control)
          ((Control)item).Background = Brushes.LimeGreen;
        else if (item is Panel)
          ((Panel)item).Background = Brushes.LimeGreen;

This bit of code is so hard to read, that it hurts my eyes!

There are two major issues with your code.
The first one is obviously the one you pointed out, which is the way you are doing your if’s.
The second is the amount of lists that you have in your code.

You also have some instance fields that you shouldn’t have, like those pesky boolean values. They can be declared inside a method.

I would replace all those lists with a dictionary. This makes the code become much simpler, as you only have to manage one variable instead of managing n variables.

So your code could be something along those lines.

public enum Position{
  LEFT, TOP_LEFT, TOP, TOP_RIGHT, RIGHT, 
  BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT,
  FULL_OUT, BEYOND, IN
}

private Position[] avaliablePositions = new Position[]{
  LEFT, TOP_LEFT, TOP, TOP_RIGHT, RIGHT, 
  BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT,
  FULL_OUT, BEYOND, IN
};

private Dictionary<Position, List<DependencyObject> objectsForPosition = new Dictionary<Position, List<DependencyObject>>();

private Position GetPositionWithinPageRect(Point startPoint, Point endPoint){
  bool inTop = (PageRect.Top <= startPoint.Y);
  bool inBottom = (PageRect.Bottom >= endPoint.Y);

  bool inLeft = (PageRect.Left <= startPoint.X);
  bool inRight = (PageRect.Right >= endPoint.X);

  bool beyond = (PageRect.Top >= endPoint.Y)
        || (PageRect.Bottom <= startPoint.Y)
        || (PageRect.Left >= endPoint.X)
        || (PageRect.Right <= startPoint.X);
  if(inTop && inLeft && inRight && inBottom){
    return Position.IN;
  }
  if (startPoint.X == 0 && startPoint.Y == 0 || !beyond && !inTop && !inLeft && !inRight && !inBottom)
    return Position.FULL_OUT;

  if(!beyond){
    if(!inTop){
      if(!inRight){
        return Position.TOP_RIGHT;
      }
      if(!inLeft){
        return Position.TOP_LEFT;
      }
      return Position.TOP;
    }
    if(!inBottom){
      if(!inRight){
        return Position.BOTTOM_RIGHT;
      }
      if(!inLeft){
        return Position.BOTTOM_LEFT;
      }
      return Position.BOTTOM;
    }
    if(!inRight){
      return Position.RIGHT;
    }
    if(!inLeft){
      return Position.LEFT;
    }
  }else{
    return Position.BEYOND;
  }
}

private bool ForeachChildIn(DependencyObject myPage, IList<DependencyObject> childList)
{
    var result = false;
    //move this on you ctor
    for(int i = 0; i < avaliablePositions.Length; ++i){
      objectsForPosition.Add(avaliablePositions[i], new List<DependencyObject>());
    }
    foreach (var item in childList)
    {
      var myVisual = item as Visual;
      if(myVisual == null) continue;

      Point relativeSartPoint = myVisual.TransformToAncestor((Visual)myPage)
                                        .Transform(new Point(0, 0));
      var aw = (double)myVisual.GetValue(FrameworkElement.ActualWidthProperty);
      var ah = (double)myVisual.GetValue(FrameworkElement.ActualHeightProperty);

      Point relativeEndPoint = new Point(relativeSartPoint.X + aw, relativeSartPoint.Y + ah);
      Position position = GetPositionWithinPageRect(relativeSartPoint, relativeEndPoint);

      if(position != Position.IN){
        if (!ForeachChildIn(item, item.getChilds().ToList())){
          if ((Visibility)item.GetValue(FrameworkElement.VisibilityProperty) == Visibility.Visible){
            if (item is Control)
                    ((Control)item).Background = Brushes.LimeGreen;
                else if (item is Panel)
                    ((Panel)item).Background = Brushes.LimeGreen;
          }
        }
        return false;
      }else{
        objectsForPosition[position].add(item);
        return true;
      }
    }
}

Attribution
Source : Link , Question Author : WiiMaxx , Answer Author : Bruno Costa

Leave a Comment