Polygon: Polygon Clipping by Shterland-Hodgman Algorithm

There are four possible cases for any given edge of given polygon against current clipping edge e.

  1. Both vertices are inside : Only the second vertex is added to the output list
  2. First vertex is outside while second one is inside : Both the point of intersection of the edge with the clip boundary and the second vertex are added to the output list
  3. First vertex is inside while second one is outside : Only the point of intersection of the edge with the clip boundary is added to the output list
  4. Both vertices are outside : No vertices are added to the output list
There are two sub-problems that need to be discussed before implementing the algorithm:-
  1. To decide if a point is inside or outside the clipper polygon
  2. To find the point of intersection of an edge with the clip boundary
Determining which side a point lies againt a line
If the vertices of the clipper polygon are given in clockwise order then all the points lying on the right side of the clipper edges are inside that polygon. This can be calculated using :

Given that the line starst from (x1,y1) and ends at (x2,y2):
\[P=(x2-x1)(y-y1)-(y2-y1)(x-x1)\]
if P<0 the point is on the right sie of the lin
P=0 the ponit is on the line
P>0 pont is on left side




Useful References

Polygon Clipping | Sutherland–Hodgman Algorithm - GeeksforGeeks

Sutherland–Hodgman algorithm - Wikipedia




Contact Points: Polygons & Clipping



Determining which side a point c lies vs a line segment (a - b)


create 2 vectors
a-b
a-c


c# - How to tell whether a point is to the right or left side of a line - Stack Overflow

user
then take the cross
isLeft(a, b, c) {
return (

public bool isLeft(Point a, Point b, Point c){ return ((b.X - a.X)*(c.Y - a.Y) - (b.Y - a.Y)*(c.X - a.X)) > 0; }


Where a = line point 1; b = line point 2; c = point to check against.
If the formula is equal to 0, the points are colinear.
If the line is horizontal, then this returns true if the point is above the line.



Taking the above ideas to the process of clipping...

We'll follow through an example in the same was a Dyn4j (but in at snail like pace), Javascript like pseudo code.

Reference edge and the incident edge are the closest edges of the two polygons being analysed, and Reference Edge is used to "clip" the Incident Edge.

The important part to remember is the relationship between the faces and the normals (we hold the outward facing normals of the polygon class in array/property this.normals).

  • normals[i] is in fact the outward facing normal of edge[i], edge[i] being the edge between vertices[i] and vertices[i+1].
  • edge[i] is normal of the left-side plane of edge[i]
  • edge[i].negate() is the normal of the right-side plan of edge[i]

To find the distance of a point p to an edge (plane), you take the dot product between the normal (needs to be unit vector) of the edge with the ( p - v1 ) or ( p - v2).


Hence:
  • distance of v2 from the left-plane of the reference edge = (reference.edge.normalized()).dot(v2 - referenceEdge.v1)
  • distance of v1 from the "right plane"of the reference edge = (reference.edge).negate().normalize().dot(v1 - referenceEdge.v1)
  • distance from point p to edge[i], we need simply take the dot product between normals[i] with ( p - vertices[i]) - since the normals are outward facing, if the resulting dot is negative it means p is "inside" the polygon (strictly speaking, "behind" the edge - it might not be entirely inside the polygon).

This is the most important step in understanding the clipping process. As long as we keep our head clear about this, then we can begin to understand how to implement the code. Of course, we need to be careful about the direction of the vectors and local vs world space...I never said this was easy.

First obtain the reference and incident edges from the reference and incident polygons

// create the reference edge vector
var refev = reference.getEdge();
// normalize it so that we have the normal vector necessary to calculate distance of a point from the side planes of the reference edge
refev.normalize();

// compute the offset of the reference edge points along the reference edge
var offset1 = -refev.dot(reference.getVertex1().getPoint());
// clip the incident edge by the reference edge's left edge
var clip1 = this.clip(incident.getVertex1(), incident.getVertex2(), refev.getNegative(), offset1);


Code to clip the incident edge segment given by v1 and v2 by reference edge


Parameters
  • v1: the first vertex of the segment to be clipped
  • v2: the second vertex of the segment to be clipped
  • n: the normalized vector of the reference edge - > hence this would be the normal relevant to the side planes
  • offset: the offset of the end point of the segment to be clipped

clip(v1, v2, n, offset) {

List<PointFeature> points = new ArrayList<PointFeature>(2);
Vector2 p1 = v1.getPoint();
Vector2 p2 = v2.getPoint();
// calculate the distance between the end points of the edge and the clip line
double d1 = n.dot(p1) - offset;
double d2 = n.dot(p2) - offset;
// add the points if they are behind the line
if (d1 <= 0.0) points.add(v1);
if (d2 <= 0.0) points.add(v2);
// check if they are on opposing sides of the line
if (d1 * d2 < 0.0) {
// get the edge vector
Vector2 e = p1.to(p2);
// clip to obtain another point
double u = d1 / (d1 - d2);
e.multiply(u);
e.add(p1);
if (d1 > 0.0) {
points.add(new PointFeature(e, v1.getIndex()));
} else {
points.add(new PointFeature(e, v2.getIndex()));
}
}
return points;
}






Useful References


https://gdcvault.com/play/1015496/Physics-for-Game (for the very advanced! Talks about multiple contacts points with rotation)

https://box2d.org/files/ErinCatto_ContactManifolds_GDC2007.pdf (this explains the key points of contact generation, with reference to SAT and GJK)

https://www.toptal.com/game/video-game-physics-part-ii-collision-detection-for-solid-objects (this covers a lot of topics and is a good read to get overall understanding of context)

https://dyn4j.org/2011/11/contact-points-using-clipping/ (this explains how to implement contact points using clipping)

http://media.steampowered.com/apps/valve/2015/DirkGregorius_Contacts.pdf (this is quite beginner friendly - goes into a fair bit of depth about different situations of contact points)

http://www.richardtonge.com/presentations/Tonge-2012-GDC-solvingRigidBodyContacts.pdf (a little bit more detail)

https://research.ncl.ac.uk/game/mastersdegree/gametechnologies/previousinformation/physics5collisionmanifolds/2017%20Tutorial%205%20-%20Collision%20Manifolds.pdf (describes clipping method)

https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc09/slides/04-GDC09_Catto_Erin_Solver.pdf (maybe one day I will understand some of this)


Centroid of Polygon

In this post we look at how to calculate the centroid of an arbitrary polygon with n-vertices.


Polygon with n-vertices

Consider a polygon with n-vertices which is bounded by n edges.

The edges of the polygon may be expressed as follows.

\[\begin{cases}x = x_i + (x_{i+}-x_i)\,t \\ y = y_i + (y_{i+}-y_i)\,t \end{cases}\quad \mbox{with} \quad \begin{cases} i = 0,1,2,\cdots,n-1 \\ i+=i+1\mod n \end{cases}\quad \mbox{and} \quad 0 \le t \le 1\]


We know the formula of the centroid is given by:

\[\vec C = \frac{1}{A}\int _A \vec r\, dA= \frac{1}{A}\iint \vec r \,dx\,dy=\frac{1}{A}(m_x,m_y)=(C_x, C_y)\]

We know how to calculate A. As for the sum of the first moment of area, we can convert the area integral into a line integral by employing Green's theorem, which states that:

Green's Theorem

Let C be a positively oriented, piecewise smooth, simple closed curve in a plane, and let D be the region bounded by C. If L and M are functions of (x, y) defined on an open region containing D and have continuous partial derivatives there, then

\[\iint \left( \frac{\partial M}{\partial x} - \frac{\partial L}{\partial y} \right) dx\,dy= \oint \left( L\,dx + M\,dy \right)\]

By substitution of \(M(x,y)=x\) and \(L(x,y)=0\) Green's Theorem becomes:

\[\iint x\,dx\,dy = \oint \frac{1}{2}x^2\,dy\]

which can be used for solving the centroid equation above.

Calculating the Centroid


x-coordinate of the centroid

By reference to the Green's therem, we can say that:

\[m_x = \iint x\,dx\,dy = \oint \frac{1}{2}x^2 \,dy\]

We need to perform the line integral around the perimeter of the polygon, edge by edge.

We have defined the y-coordinate of each edge as:

\[y = y_i + (y_{i+}-y_i)\,t\]

Based on which we can say that:

\[\frac{dy}{dt} = (y_{i+}-y_i)\]

It follows that:

\[m_x = \sum_{i=0}^{n-1}\frac{1}{2}\int_0^1\left[x_i + (x_{i+}-x_i)\,t\right]^2\,(y_{i+}-y_i)dt\]

Which we can start expanding as follows:

\[\begin{equation}\begin{split} m_x &= \frac{1}{2}\sum_{i=0}^{n-1}\int_0^1(y_{i+}-y_i)\left[x_i^2 + (x_{i+}-x_i)^2t^2+2x_i(x_{i+}-x_i)t\right]\,dt\\&=\frac{1}{2}\sum_{i=0}^{n-1}(y_{i+}-y_i)\left[x_i^2t + \frac{1}{3}(x_{i+}-x_i)^2t^3+x_i(x_{i+}-x_i)t^2\right]_0^1\\&=\frac{1}{2}\sum_{i=0}^{n-1}(y_{i+}-y_i)\left[x_i^2 + \frac{1}{3}(x_{i+}-x_i)^2+x_i(x_{i+}-x_i)\right]\\&=\frac{1}{6}\sum_{i=0}^{n-1}(y_{i+}-y_i)\left[x_{i+}^2 +x_ix_{i+} +x_i^2\right]\\\end{split}\end{equation}\]\[m_y = \iint y\,dx\,dy = \oint -\frac{1}{2}y^2 \,dx = -\frac{1}{2}\sum_{i=0}^{n-1}(x_{i+}-x_i)\int_0^1\left[y_i + (y_{i+}-y_i)\,t\right]^2\,dt\]

The last expression is a telescoping sequence as below:

\[\begin{equation}\begin{split}y_1(x_1^2+x_1x_0+x_o^2)-y_o(x_1^2+x_1x_0+x_0^2)\\+y_2(x_2^2+x_2x_1+x_1^2)-y_1(x_2^2+x_2x_1+x_1^2)\\\cdot\,\cdot\,\cdot\,\cdot\,\\+y_n(x_n^2+x_nx_{n-}+x_{n-}^2)-y_{n-}(x_n^2+x_nx_{n-}+x_{n-}^2)\\\end{split}\end{equation}\]

which in turn can be expressed as:

\[\begin{equation}\begin{split}y_1x_1^2+y_1x_1x_0+y_1x_0^2-y_0x_1^2-y_0x_1x_0-y_0x_0^2\\+y_2x_2^2+y_2x_2x_1+y_2x_1^2-y_1x_2^2-y_1x_2x_1-y_1x_1^2\\\cdot\,\cdot\,\cdot\,\cdot\,\\+y_nx_n^2+y_nx_nx_{n-}+y_nx_{n-}^2-y_{n-}x_n^2-y_{n-}x_nx_{n-}-y_{n-}x_{n-}^2\\\end{split}\end{equation}\]

The first and last term of each line cancel themselves out, leaving you with:

\[\frac{1}{6}\sum_{i=0}^{n-1}(y_{i+}x_ix_{i+}+y_{i+}x_i^2-y_ix_{i+}^2- y_ix_i x_{i+})\]

which can then be simplied to:

\[\frac{1}{6}\sum_{i=0}^{n-1}(y_{i+}x_i-y_ix_{i+})(x_i+x_{i+})\]

y-coordinate of the centroid

It is seen that everything is the same if we just exchange x and y, except for the minus sign, hence:

\[\begin{equation}\begin{split}m_y &= -\frac{1}{6}\sum_{i=0}^{n-1}(x_{i+}y_i-x_i y_{i+})(y_i+y_{i+})\\&=\frac{1}{6}\sum_{i=0}^{n-1}(x_iy_{i+}-x_{i+}y_i)(y_i+y_{i+})\end{split}\end{equation}\]


Useful References

Centroid - Wikipedia

geometry - Why doesn't a simple mean give the position of a centroid in a polygon? - Mathematics Stack Exchange

Numerical Integration: 2nd and 4th order Runge-Kutta schemes

Second-order Runge-Kutta scheme (RK2) There are several variations of the second order Runge-Kutta schemes of numerical integration. They ar...