Here's one possible solution using a function that rotates a point around the origin (0,0):
The strategy is to transpose the coordinates to a frame of reference around one of the known points. Then apply the relative rotation of the other known point to compute the unknown third point.
If we name the 3 points of the triangle A, B and C with C being the unknown after moving A and B, the process would go as follows:
- Convert B and C into relative coordinates having A as their origin ==> B0 and C0
- Compute the angle of B0 from the origin. That will be the original angle of the AB segment (which can easily be obtained using math.atan2)
- Convert newB point to relative coordinates with newA as origin ==> newB0
- Compute the angle of newB0 from the origin
- The delta between angles of B0 and newB0 can be applied to the original C0 point to produce newC0 (using the point rotation function)
- Transpose newC0 to newC by translation from newA
...
import math
def rotatePoint(x,y,angle):
s,c = math.sin(angle), math.cos(angle)
return (x*c-y*s, x*s+y*c)
def getNewC(A,B,C,newA,newB):
Ax,Ay = A
Bx,By = B
Cx,Cy = C
B0x,B0y = Bx-Ax, By-Ay
oldAngleAB = math.atan2(B0y,B0x)
newAx,newAy = newA
newBx,newBy = newB
newB0x,newB0y = newBx-newAx, newBy-newAy
newAngleAB = math.atan2(newB0y,newB0x)
C0x,C0y = Cx-Ax, Cy-Ay
newC0x,newC0y = rotatePoint(C0x,C0y,newAngleAB - oldAngleAB)
newCx,newCy = newAx+newC0x, newAy+newC0y
return newCx,newCy
outut: (using turtle to illustrate)
import turtle
t = turtle.Turtle()
A = (10,10)
B = (60,10)
C = (30,120)
t.penup()
t.goto(*A)
t.pendown()
t.goto(*B)
t.goto(*C)
t.goto(*A)
newA = (-10,-10)
newB = (-10,-60)
newC = getNewC(A,B,C,newA,newB)
t.pen(pencolor="red")
t.penup()
t.goto(*newA)
t.pendown()
t.goto(*newB)
t.goto(*newC)
t.goto(*newA)
newA = (-40,40)
newB = (-70,80)
newC = getNewC(A,B,C,newA,newB)
t.pen(pencolor="blue")
t.penup()
t.goto(*newA)
t.pendown()
t.goto(*newB)
t.goto(*newC)
t.goto(*newA)
Note that this does not perform any scaling. It assumes that the distance between the two base points remains the same after being moved. If, eventually, you do need scaling, it can be added at the end in the transposition from newC0 to newC:
scale = ((newB0x**2+newB0y**2)/(B0x**2+B0y**2))**0.5
newCx,newCy = newAx+newC0x*scale, newAy+newC0y*scale
output:
newA = (110,110)
newB = (150,220)
newC = getNewC(A,B,C,newA,newB)
t.pen(pencolor="purple")
t.penup()
t.goto(*newA)
t.pendown()
t.goto(*newB)
t.goto(*newC)
t.goto(*newA)
