Download SliceRectangleSample.zip, last updated 10/02/2013 (23.18 KB)

Download
  • md5: 1e8ccdf10305cc43789e4fa28c96006b
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;

namespace SliceRectangleSample
{
  // Cyotek Slice Rectangle Sample
  // Copyright (c) 2013 Cyotek. All Rights Reserved.
  // http://cyotek.com
  // http://cyotek.com/blog/dividing-up-a-rectangle-based-on-pairs-of-points-using-csharp

  // If you use this code in your applications, attribution or donations are welcome.

  internal class Settings
  {
    #region Constructors

    public Settings()
    {
      this.Segments = new List<Segment>();
    }

    #endregion

    #region Properties

    public List<Segment> Segments { get; set; }

    public Size Size { get; set; }

    private IDictionary<Point, SegmentPoint> Points { get; set; }

    private HashSet<Rectangle> Rectangles { get; set; }

    #endregion

    #region Members

    public void Calculate()
    {
      this.CalculatePoints();
      this.CalculateRectangles();
    }

    public SegmentPoint[] GetPoints()
    {
      return this.Points != null ? this.Points.Values.ToArray() : new SegmentPoint[0];
    }

    public Rectangle[] GetRectangles()
    {
      return this.Rectangles != null ? this.Rectangles.ToArray() : new Rectangle[0];
    }

    public void Load(string fileName)
    {
      this.Segments = new List<Segment>();
      this.Points = null;

      using (FileStream stream = File.OpenRead(fileName))
      {
        using (TextReader reader = new StreamReader(stream))
        {
          string[] data;
          int segmentCount;

          data = reader.ReadLine().Split(',');
          this.Size = new Size(Convert.ToInt32(data[0]), Convert.ToInt32(data[1]));

          segmentCount = Convert.ToInt32(reader.ReadLine());

          for (int i = 0; i < segmentCount; i++)
          {
            Segment segment;

            data = reader.ReadLine().Split(',');

            segment = new Segment { Location = new Point(Convert.ToInt32(data[0]), Convert.ToInt32(data[1])), Size = Convert.ToInt32(data[2]), Orientation = (SegmentOrientation)Enum.Parse(typeof(SegmentOrientation), data[3], true) };

            this.Segments.Add(segment);
          }
        }
      }

      this.Calculate();
    }

    public void Save(string fileName)
    {
      using (FileStream stream = File.OpenWrite(fileName))
      {
        using (TextWriter writer = new StreamWriter(stream))
        {
          writer.WriteLine("{0},{1}", this.Size.Width, this.Size.Height);
          writer.WriteLine(this.Segments.Count);
          foreach (Segment segment in this.Segments)
            writer.WriteLine("{0},{1},{2},{3}", segment.Location.X, segment.Location.Y, segment.Size, segment.Orientation);
        }
      }
    }

    private void CalculatePoints()
    {
      List<Segment> segments;

      segments = new List<Segment>();
      this.Points = new Dictionary<Point, SegmentPoint>();

      // add segments representing the edges
      segments.Add(new Segment { Location = Point.Empty, Size = this.Size.Width, Orientation = SegmentOrientation.Horizontal });
      segments.Add(new Segment { Location = new Point(0, this.Size.Height), Size = this.Size.Width, Orientation = SegmentOrientation.Horizontal });
      segments.Add(new Segment { Location = Point.Empty, Size = this.Size.Height, Orientation = SegmentOrientation.Vertical });
      segments.Add(new Segment { Location = new Point(this.Size.Width, 0), Size = this.Size.Height, Orientation = SegmentOrientation.Vertical });

      // add the rest of the segments
      segments.AddRange(this.Segments);

      segments.Sort((a, b) =>
      {
        int result = a.Location.X.CompareTo(b.Location.X);
        if (result == 0)
          result = a.Location.Y.CompareTo(b.Location.Y);
        return result;
      });

      foreach (Segment segment in segments)
      {
        Segment currentSegment;

        // add the segment points
        this.UpdatePoint(segment.Location, segment.Orientation == SegmentOrientation.Horizontal ? SegmentPointConnections.Left : SegmentPointConnections.Top);
        this.UpdatePoint(segment.EndLocation, segment.Orientation == SegmentOrientation.Horizontal ? SegmentPointConnections.Right : SegmentPointConnections.Bottom);

        // calculate any intersecting points
        currentSegment = segment;
        foreach (Segment otherSegment in segments.Where(s => s != currentSegment))
        {
          Point intersection;

          intersection = Intersection.FindLineIntersection(segment.Location, segment.EndLocation, otherSegment.Location, otherSegment.EndLocation);
          if (!intersection.IsEmpty)
          {
            SegmentPointConnections flags;

            flags = SegmentPointConnections.None;
            if (intersection != segment.Location && intersection != segment.EndLocation)
            {
              if (segment.Orientation == SegmentOrientation.Horizontal)
                flags |= (SegmentPointConnections.Left | SegmentPointConnections.Right);
              else
                flags |= (SegmentPointConnections.Top | SegmentPointConnections.Bottom);
            }
            else if (intersection != otherSegment.Location && intersection != otherSegment.EndLocation)
            {
              if (otherSegment.Orientation == SegmentOrientation.Horizontal)
                flags |= (SegmentPointConnections.Left | SegmentPointConnections.Right);
              else
                flags |= (SegmentPointConnections.Top | SegmentPointConnections.Bottom);
            }

            if (flags != SegmentPointConnections.None)
              this.UpdatePoint(intersection, flags);
          }
        }
      }
    }

    private void CalculateRectangles()
    {
      SegmentPoint[] horizontalPoints;
      SegmentPoint[] verticalPoints;

      this.Rectangles = new HashSet<Rectangle>();
      horizontalPoints = this.Points.Values.OrderBy(p => p.X).ToArray();
      verticalPoints = this.Points.Values.OrderBy(p => p.Y).ToArray();

      foreach (SegmentPoint topLeft in this.Points.Values.Where(p => p.Connections.HasFlag(SegmentPointConnections.Left | SegmentPointConnections.Top)))
      {
        SegmentPoint topRight;
        SegmentPoint bottomLeft;

        topRight = horizontalPoints.FirstOrDefault(p => p.X > topLeft.X && p.Y == topLeft.Y && p.Connections.HasFlag(SegmentPointConnections.Right | SegmentPointConnections.Top));
        bottomLeft = verticalPoints.FirstOrDefault(p => p.X == topLeft.X && p.Y > topLeft.Y && p.Connections.HasFlag(SegmentPointConnections.Left | SegmentPointConnections.Bottom));

        if (topRight != null && bottomLeft != null)
        {
          SegmentPoint bottomRight;

          bottomRight = horizontalPoints.FirstOrDefault(p => p.X == topRight.X && p.Y == bottomLeft.Y && p.Connections.HasFlag(SegmentPointConnections.Right | SegmentPointConnections.Bottom));

          if (bottomRight != null)
          {
            Rectangle rectangle;

            rectangle = new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);

            this.Rectangles.Add(rectangle);
          }
        }
      }
    }

    private void UpdatePoint(Point location, SegmentPointConnections connections)
    {
      SegmentPoint point;

      if (!this.Points.TryGetValue(location, out point))
      {
        point = new SegmentPoint { Location = location, Connections = connections };
        this.Points.Add(point.Location, point);
      }
      else if (!point.Connections.HasFlag(connections))
        point.Connections |= connections;
    }

    #endregion
  }
}

Donate

Donate