# Flipping polygon around arbitrary axis in QGIS

I want to flip a vector polygon about an arbitrary axis. What I would like to do is select the polygon to flip, pick two points (A & B in image below) identifying the axis about which the flip will occur, and get a result that looks like the red-dashed polygon.

What I have tried: searching for 'Flip', 'Mirror', 'Transform' in QGIS processing tools and web searches.

As a workaround, I've been using the 'Shape Tools' plugin 'Flip Horiz/Vert' in combination with QGIS Vector Tools 'Rotate'. • Phew... I guess you need to create a line from your points, then extend it, then calculate the distance and direction of each polygon vertex to the line, then translate each vertex by that distance, and finally convert your vertices back to a line and that to a polygon. I doubt this is possible without creating a new layer.
– Erik
Jun 8, 2022 at 13:45

I wrote this code that reflects a polygon between a line created by two points. I don't know the best way for you to input the feature and the points, so the implementation is very basic and you'll probably need to fix some lines for your main purpose.

Note: I am not an expert mathematician nor a python programmer. Maybe this script is inefficient but the important thing is to get the idea.

Notes

• This script is very basic, so it works only with single part polygon geometries.
• This code modifies and overrides the features geometries, so be careful
• This include snapping tools.

You only need to paste the code in the QGIS python console, then select the feature you want to reflect, run the code, left click first point of the reflection line right click second point of the reflection line.

``````def reflectPoints(input_points, refl_pt_a, refl_pt_b):
try:
m = (refl_pt_a.y() - refl_pt_b.y()) / (refl_pt_a.x() - refl_pt_b.x()) # get the slope of the reflection line
b = refl_pt_a.y() - m * refl_pt_a.x() # get how 'shifted' the line is
try:
inv_m = -1 / m # get the slope of perpendicular line to the reflection line
for x, y in input_points: # loop throw the list of points
# create a perpendicular line that touches the n point of input_points
b_n = y - inv_m * x # find how 'shifted' the perpendicular line is
l_x_coord = (b_n - b) / (m - inv_m) # get the x coordinate of the intersection between the reflection line and the perpendicular line
l_y_coord = m * l_x_coord + b # get the y coordinate of the intersection between the reflection line and the perpendicular line
new_x = 2 * l_x_coord - x # different approach of the Midpoint theorem to find the x coordinate reflected
new_y = 2 * l_y_coord - y # different approach of the Midpoint theorem to find the y coordinate reflected
yield QgsPointXY(new_x, new_y)
except ZeroDivisionError: # handle reflection across horizontal line (undefined slope)
for x, y in input_points:
l_y_coord = refl_pt_a.y()
new_x = x
new_y = 2 * l_y_coord - y
yield QgsPointXY(new_x, new_y)
except ZeroDivisionError: # handle reflection across vertical line (no slope)
for x, y in input_points:
l_x_coord = refl_pt_a.x()
new_x = 2 * l_x_coord - x
new_y = y
yield QgsPointXY(new_x, new_y)
canvas = iface.mapCanvas()
map_tool.setAutoSnapEnabled(True)
map_tool.startCapturing()
canvas.setMapTool(map_tool)
old_point = False # this variable will store the first point of the reflection line
def getPoints(mouse):
point = mouse.mapPoint()
button = mouse.button()
global old_point
if not old_point and button == 1:
old_point = QgsPointXY(point)
elif old_point and button == 2:
input_layer = iface.activeLayer() # get active layer
feature = next(input_layer.getSelectedFeatures()) # get the selected layer, here it only takes one feature if more than one where selected
input_points = feature.geometry().asPolygon() # get the geometry of only one polygon if multipolygon geometry
output_points = list(reflectPoints(input_points, point, old_point)) # reflect the vertices
input_layer.startEditing()
geometry = QgsGeometry.fromPolygonXY([output_points])
input_layer.changeGeometry(feature.id(), geometry)
old_point = False
input_layer.commitChanges()
global map_tool
global canvas
canvas.unsetMapTool(map_tool)

``````

You can use the "Geometry Generator" to dynamically create a copy (visualization only) of your polygon, flipped around the line on the layer `axis` using the following expression. Whenever you change the line, the flipped polygon will adapt immediately:

``````make_polygon(
make_line (
array_foreach (
generate_series (1,  num_points( \$geometry)),
with_variable (
'line',
make_line (
point_n( \$geometry, @element),
closest_point(
extend (
overlay_nearest(
'axis',  --change the name to the name of the line layer you use
\$geometry
),
100000, -- adapt these distances on this and the next line (just needed in case the axis is shorter then the polygon)
100000
),
point_n (\$geometry, @element)
)
),
end_point (
extend (@line,0,length(@line))
)
)
)
)
)
``````

Red: initial polygon, blue: flipped polygon; black: axis 