Finding the centroid of a polygon in Python

Question:

I want to calculate the centroid of a figure formed by the points: (0,0), (70,0), (70,25), (45, 45), (45, 180), (95, 188), (95, 200), (-25, 200), (-25,188), (25,180), (25,45), (0, 25), (0,0).

I know that the correct result for the centroid of this polygon is x = 35 and y = 100.4615, but the code below does not return the correct values (figure of the polygon below).

enter image description here

import numpy as np
import matplotlib.pyplot as plt

poligono = np.array([(0,0), (70,0), (70,25), (45,45), (45,180), (95,188), (95,200), (-25,200), (-25, 188), (25,180), (25,45), (0,25), (0,0)])

x = pontos[:, 0]
y = pontos[:, 1]

points_array_2 = np.array(points)

centroid = np.mean(points_array_2, axis=0)

print("Centroide:", centroid)

enter image description here

I would like to know if someone can help me correctly calculate the centroid of the polygon.

Asked By: Victor Soares

||

Answers:

Fixed:

def centroid(vertices):
    x, y = 0, 0
    n = len(vertices)
    signed_area = 0
    for i in range(len(vertices)):
        x0, y0 = vertices[i]
        x1, y1 = vertices[(i + 1) % n]
        # shoelace formula
        area = (x0 * y1) - (x1 * y0)
        signed_area += area
        x += (x0 + x1) * area
        y += (y0 + y1) * area
    signed_area *= 0.5
    x /= 6 * signed_area
    y /= 6 * signed_area
    return x, y

x, y = centroid(vertices)
print(x, y)

Produces:

35.0 100.46145124716553
Answered By: yukako

Here’s some code. Explanations follow.

import numpy as np

polygon = np.array(
    [
        (0,0), (70,0), (70,25), (45, 45), (45, 180), (95, 188),
        (95, 200), (-25, 200), (-25,188), (25,180), (25,45), (0, 25),
    ],
    dtype=np.float64,
)

# Same polygon, but with vertices cycled around. Now the polygon
# decomposes into triangles of the form origin-polygon[i]-polygon2[i]
polygon2 = np.roll(polygon, -1, axis=0)

# Compute signed area of each triangle
signed_areas = 0.5 * np.cross(polygon, polygon2)

# Compute centroid of each triangle
centroids = (polygon + polygon2) / 3.0

# Get average of those centroids, weighted by the signed areas.
centroid = np.average(centroids, axis=0, weights=signed_areas)

print("Centroid:", centroid)

The result of running this code on my machine is the one you expect:

$ python polygon_centroid.py
Centroid: [ 35.         100.46145125]

The basic idea is that we decompose the shape into triangles. We can compute the centroid for each triangle via the obvious formula (it’s the mean of the vertices). To compute the centroid of the whole polygon, we just have to compute the average of the centroids of the constituent triangles, with each triangle weighted by its (signed) area.

What makes this task especially easy for a polygon is that we can allow ourselves to include "negative" triangles – that is, we can express the polygon as a sum and difference of triangles. Provided we keep track of the signs in the areas, everything works out. So there’s no need to worry about whether your polygon is convex or not, for example, or whether the origin is inside the polygon.

In the code above, we simply decompose into the triangles formed by consecutive vertices together with the origin.

See this Wikipedia page for more.

Answered By: Mark Dickinson

The centroid of a serie of ALIGNED points is the mean of them.

For a closed. non-self-intersecting, polygon you must use some more compliated formulas
See "Of a polygon" at wikipedia centroid

A note aside. I guess you also need the inertia of the beam. For that I advice to decompese into rentangles and triangles and then use the Steiner’s Theorema https://es.wikipedia.org/wiki/Teorema_del_eje_paralelo

Answered By: Ripi2

Very good and detailed answers have been already provided. In case you do not want to do the math from scratch, I highly suggest to use the shapely library when dealing with polygons.

To compute the centroid of the polygon given the coordinates of its vertices, you can do the following:

from shapely.geometry import Polygon
polygon = Polygon([(0,0), (70,0), (70,25), (45, 45), (45, 180), (95, 188), (95, 200), (-25, 200), (-25,188), (25,180), (25,45), (0, 25)])
print(polygon.centroid)
>>> POINT (35 100.46145124716553)
Answered By: blunova
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.