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 = QgsMapToolCapture(canvas, iface.cadDockWidget(), QgsMapToolCapture.CaptureLine)
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()[0] # 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)
map_tool.cadCanvasPressEvent = getPoints