Add N Pixel Buffer to Polygon (Region/Path) While Maintaining Centroid in C#

390 views Asked by At

The Problem: Add n pixel buffer to an existing polygon (guaranteed to be closed, non-overlapping, and points in clockwise formation) while maintaining the centroid of the polygon.

Current: I have a PolyRegion class which contains a System.Drawing Path and System.Drawing Region. When I instantiate the class I'd add the factor buffer to the path and scale/transform it. The result is offset instead if scaled with respect to the centroid.

Example: The green polygon is the original. When I scale it by factor of n, I get/want the purple polygon (centered on centroid).

enter image description here

Question: How can I scale with respect to the centroid? AM I better off scaling each point in the point array or scaling the Path/Region?

Code:

public PolyRegion(Int32 Id, List<Point> Points)
{
    this.Id = Id;
    this.Points = Points;
    this.Path = this.CreatePath();

    float factor = 10;
    float wScale = (float)((this.Path.GetBounds().Width - factor) / this.Path.GetBounds().Width);
    float hScale = (float)((this.Path.GetBounds().Height - factor) / this.Path.GetBounds().Height);
    Matrix transformMatrix = new Matrix();
    transformMatrix.Scale(wScale, hScale);
    this.Path.Transform(transformMatrix);

    this.Region = new Region(this.Path);
    this.Area = CalculateArea();  
}
2

There are 2 answers

3
SJuan76 On

This is more a mathematical/geometric issue than a programming one:

1) Translate figure from centroid position (x, y) to (0,0) coordinate

2) Scale by the factor you desire.

3) Translate back to original centroid.

0
David J Barnes On

I decided to ditch matrix and region scale and transforms and go with a more pure approach.

First I calculate the centroid of my polgon:

private Point GetCentroid()
{
int centroidX = 0;
int centroidY = 0;
int pointCount = this.Points.Count();

for (int i = 0; i < pointCount; i++)
{
centroidX = centroidX + this.Points[i].X;
centroidY = centroidY + this.Points[i].Y;
}

centroidX = centroidX / pointCount;
centroidY = centroidY / pointCount;

return new Point(centroidX, centroidY);
}

Then loop through each point and buffer it by S and T (my buffer factor):

private List<Point> GetBufferedPoints()
{
int c = this.Centroid.X;
int d = this.Centroid.Y;
int s = this.BufferFactor;
int t = this.BufferFactor;
int pointCount = this.Points.Count();
PointsBuffered = new List<Point>();

for (int i = 0; i < pointCount; i++)
{
int x = this.Points[i].X;
int y = this.Points[i].Y;
PointsBuffered.Add(new Point((s * (x - c)) + c, (t * (y - d)) + d));
}

return PointsBuffered;
}

Result:

enter image description here