WKT moving polygon to center

111 views Asked by At

I have a WKT object and want to move its center to the origin (0,0). Here is an example and what I tried:

from shapely import wkt

poly_str = 'POLYGON ((14.217343909259455 -2.9030822376560224, 16.003619392313993 -2.639545672126154, 16.363681477720576 -5.080080154489572, 14.577405994666037 -5.34361672001944, 14.217343909259455 -2.9030822376560224))'
geom = wkt.loads(poly_str)

normalized = geom.normalize() # this does nothing
normalized == geom # TRUE


centroid = geom.centroid
moved_geom = geom - centroid  # this seems logical, but does not achieve what I want

print(moved)
>>>> 'POLYGON ((16.003619392313993 -2.639545672126154, 16.363681477720576 -5.080080154489572, 14.577405994666037 -5.34361672001944, 14.217343909259455 -2.9030822376560224, 16.003619392313993 -2.639545672126154))'

Why is that last polygon not moved by the amount of the centroid and how would I obtain a shifted polygon from my original whose centroid would be at (0,0)?

1

There are 1 answers

4
Musabbir Arrafi On BEST ANSWER

You are actually on the right track, but there's a mistake in how you're calculating the moved geometry. The subtraction operation geom - centroid is not directly supported in Shapely for moving geometries. Instead, you should manually translate the coordinates of each point. This should be your solution:

from matplotlib import pyplot as plt
from shapely import wkt
from shapely.affinity import translate

poly_str = 'POLYGON ((14.217343909259455 -2.9030822376560224, 16.003619392313993 -2.639545672126154, 16.363681477720576 -5.080080154489572, 14.577405994666037 -5.34361672001944, 14.217343909259455 -2.9030822376560224))'
geom = wkt.loads(poly_str)

# Calculate the centroid
centroid = geom.centroid

# Calculate the translation vector
translation_vector = (-centroid.x, -centroid.y)

# Perform the translation on each point
moved_coords = [(x + translation_vector[0], y + translation_vector[1]) for x, y in geom.exterior.coords]

# Create a new geometry with the moved coordinates
moved_geom = wkt.loads('POLYGON ((' + ', '.join([f'{x} {y}' for x, y in moved_coords]) + '))')
print("Original GEOM: \n",geom.wkt)
print("Moved GEOM: \n",moved_geom.wkt)

# Plot the original and moved geometries
plt.figure(figsize=(10, 5))

# Plot the original geometry
plt.subplot(1, 2, 1)
plt.plot(*geom.exterior.xy, label='Original Exterior', color='blue')
for interior in geom.interiors:
    plt.plot(*interior.xy, label='Original Interior', color='red')
plt.title('Original Geometry')
plt.legend()

# Plot the moved geometry
plt.subplot(1, 2, 2)
plt.plot(*moved_geom.exterior.xy, label='Moved Exterior', color='blue')
for interior in moved_geom.interiors:
    plt.plot(*interior.xy, label='Moved Interior', color='red')
plt.title('Moved Geometry')
plt.legend()

plt.tight_layout()
plt.show()

Output:

Original GEOM: 
 POLYGON ((14.217343909259455 -2.9030822376560224, 16.003619392313993 -2.639545672126154, 16.363681477720576 -5.080080154489572, 14.577405994666037 -5.34361672001944, 14.217343909259455 -2.9030822376560224))

Moved GEOM: 
 POLYGON ((-1.0731687842305604 1.0884989584167752, 0.713106698823978 1.3520355239466437, 1.0731687842305604 -1.0884989584167744, -0.713106698823978 -1.3520355239466428, -1.0731687842305604 1.0884989584167752))

enter image description here See, your example polygon doesn't have any hole cut in it, so the interior points are not taken into consideration.

Moving both interior and exterior points to the center

If you have a polygon with both interior and exterior points, here's how you move it to the center

import matplotlib.pyplot as plt
from shapely import wkt
from shapely.affinity import translate

# Define the polygon string with a hole
poly_str = 'POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10), (12 12, 18 12, 18 18, 12 18, 12 12))'

# Load the original geometry
geom = wkt.loads(poly_str)

# Calculate the centroid
centroid = geom.centroid

# Calculate the translation vector
translation_vector = (-centroid.x, -centroid.y)

# Perform the translation on each point (exterior and interior)
moved_coords = []
for ring in geom.interiors:  # Process interior rings (holes)
    moved_ring = [(x + translation_vector[0], y + translation_vector[1]) for x, y in ring.coords]
    moved_coords.append(moved_ring)

moved_exterior = [(x + translation_vector[0], y + translation_vector[1]) for x, y in geom.exterior.coords]
moved_coords.append(moved_exterior)

# Construct the moved geometry using its WKT representation
moved_geom_wkt = 'POLYGON ((' + '), ('.join([', '.join([f'{x} {y}' for x, y in ring]) for ring in moved_coords]) + '))'
moved_geom = wkt.loads(moved_geom_wkt)

print("Original GEOM: \n",geom.wkt)
print("Moved GEOM: \n",moved_geom.wkt)

# Plot the original and moved geometries
plt.figure(figsize=(10, 5))

# Plot the original geometry
plt.subplot(1, 2, 1)
plt.plot(*geom.exterior.xy, label='Original Exterior', color='blue')
for interior in geom.interiors:
    plt.plot(*interior.xy, label='Original Interior', color='red')
plt.title('Original Geometry')
plt.legend()

# Plot the moved geometry
plt.subplot(1, 2, 2)
plt.plot(*moved_geom.exterior.xy, label='Moved Exterior', color='blue')
for interior in moved_geom.interiors:
    plt.plot(*interior.xy, label='Moved Interior', color='red')
plt.title('Moved Geometry')
plt.legend()

plt.tight_layout()
plt.show()

Output:

Original GEOM: 
 POLYGON ((10 10, 20 10, 20 20, 10 20, 10 10), (12 12, 18 12, 18 18, 12 18, 12 12))
Moved GEOM: 
 POLYGON ((-3 -3, 3 -3, 3 3, -3 3, -3 -3), (-5 -5, 5 -5, 5 5, -5 5, -5 -5))

enter image description here