#!/usr/bin/env python # Experiments with coefficients of a geometric plane # Resources: # http://www.wolframalpha.com/input/?i=plane+through+(1,-2,0),(4,-2,-2),(4,1,4)&lk=3 # ==> 2 x - 6 y + 3 z + 14 == 0 # Translate a point relative to some origin from __future__ import print_function def translate(point, origin): return tuple([a - b for a, b in zip(point, origin)]) # Given two points in 3d space, define a vector def vector(p1, p2): return tuple([b - a for a, b in zip(p1, p2)]) # Given two vectors in a plane, find the normal vector def normal(u, v): # A normal vector is the cross-product of two coplanar vectors return tuple( [ u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0], ] ) def plane_from_three_points(P, Q, R): u = vector(P, Q) v = vector(P, R) n = normal(u, v) # Find the coefficients (A, B, C) = n # The equation of the plane is thus Ax+By+Cz+K=0. # Solve for K to get the final coefficient (x, y, z) = P K = -(A * x + B * y + C * z) return (A, B, C, K) # find the Z offset for any x,y # z = -(Ax + By + K) / C def calcz(x, y, plane, translation=(0, 0, 0)): (A, B, C, K) = plane (tx, ty, tz) = translation return -(A * (x - tx) + B * (y - ty) + K) / C + tz # Verify a point is on this plane def validate(plane, point): (A, B, C, K) = plane (x, y, z) = point return z == calcz(x, y, plane) def verify_plane(points): print(" ", "\n ".join([str(p) for p in points])) plane = plane_from_three_points(*points) print("Plane coordinates: ", plane) if plane[2] == 0: print(" Error: points are colinear") return valid = True for p in points: if not validate(plane, p): print("Failed: sample point not on plane, ", p) valid = False print("Validation:", "Failed" if not valid else "Passed") samples = [ # canonical example [(1, -2, 0), (4, -2, -2), (4, 1, 4)], # three colinear points (infinite planes) [(2, 2, 2), (4, 4, 4), (10, 10, 10)], # Extreme tilt example in mm [(57, 123, -5), (200, 0, 35), (0, 207, 2)], # Some more examples in um [(0, 0, 1300), (200000, 200000, 3500), (0, 150000, -1000)], [(20000, 20000, -300), (220000, 120000, -1700), (120000, 220000, -700)], # some example in tenths of mm [(200, 200, -300), (2200, 1200, -1700), (1200, 2200, -700)], [(20000, 20000, -300), (220000, 120000, -1700), (120000, 220000, -700)], [(200, 200, -300), (2200, 1200, -1700), (1200, 2200, -700)], ] for points in samples: verify_plane(points) print("====[Translated]=========") # Translate plane to origin at P (simplifies by removing K coefficient) # A*x' + B*y' + C*z' = 0 P = points[0] T = translate((0, 0, 0), P) xpoints = [translate(p, P) for p in points] verify_plane(xpoints) print("=========================\n")