Finding the centroid of a polygon in Python
Asked Answered
H

4

6

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 (source), but the code below does not return the correct values (figure of the polygon below).

import numpy as np

points = 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)])
centroid = np.mean(points, axis=0)
print("Centroid:", centroid)

Output: Centroid: [32.30769231 98.15384615]

How can I correctly calculate the centroid of the polygon?

enter image description here

Helga answered 10/3, 2023 at 17:2 Comment(1)
Are you looking for the formula to calculate the location of the centroid in general or the python implementation?Nestle
D
4

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
Disincentive answered 10/3, 2023 at 17:28 Comment(0)
A
8

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)
Averett answered 12/3, 2023 at 0:59 Comment(0)
R
6

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.

Romaromagna answered 10/3, 2023 at 18:11 Comment(0)
D
4

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
Disincentive answered 10/3, 2023 at 17:28 Comment(0)
F
2

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

Falkner answered 10/3, 2023 at 20:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.