Transpose 3D coordinates on a plane to a new 2D coordinate system

Viewed 1711

I have been working on a personal project to produce an image of the integer solutions to the equation x^2 + y^2 + z^2 = S where 'S' is any integer.

In other words, I am looking for all the 3D points [x,y,z] where x, y, and z are all perfect square integers and x + y + z = S

For example, S = 2809 will have solutions:

  • [144, 1296, 1369],
  • [144, 729, 1936],
  • [0, 0, 2809]
  • ... plus all permutations of the above (i.e. 144+729+1936 = 1936+729+144)

Before I get to my question, here is a small tangent for some context:

All of the solutions to the general equation x + y + z = S will lie on a 2D plane defined by:

  • A = [S, 0, 0]
  • B = [0, S, 0]
  • C = [0, 0, S]

Here is a graph of all solutions (not just square points) to x + y + z = 50 to illustrate that all of the solutions to this equation will lie on the same plane bounded by ABC defined above. Notice that the tips of the triangle below are: [50, 0, 0], [0, 50, 0], and [0, 0, 50]

ABC plane

Back to my question: After finding the square solution points, I want to transpose the 3D solution points into 2D coordinates based on the ABC plane with A as (0,0), B is the max 'x' value, and C is the max 'y' value. I then hope to output these solutions to an image file.

My linear algebra knowledge is sparse, and I have been unable to find a method to transpose 3D coordinates into 2D plane coordinates based on 3 non-colinear points.

My code is currently in python, but an algorithmic/mathematical answer is just as good!

Any help is much appreciated!

2 Answers

As I see it, you can already find your (x, y, z) points, and your question is about a way to project them onto a plane.

Please refer to projection matrix to learn how to project the 3d world onto an image plane of your choosing.

Specifically, you will have to express your (x, y, z) coordinates as homogeneous coordinates by refering to them as (x, y, z, 1), and to multiply them by a relevant camera matrix which is orthogonal to the plane on which you need to cast them.

This will yield 2d homogeneous coordinates of the form (x', y', f) from which you will be able to obtain the projected coordinates by (x_projected, y_projected) = (x'/f, y'/f).

OpenCV is your friend.

Recap:

  1. Input: n (x, y, z) points
  2. Obtain projection (camera) matrix M of size (4, 3) using opencv or calculate yourself using whatever tools.
  3. Add last dimension 1 to all points to get them as 3d homogeneous coordinates: n points (x, y, z, 1)
  4. Multiply all points by the matrix to obtain projected points as 2d homogeneous coordinates: M * (x, y, z, 1)^T = (x', y', f)
  5. Get n actual 2d projected coordinates (relative to camera center as defined by the M matrix) by (x, y) = (x'/f, y'/f)

Bonus: you can stack all your (x, y, z, 1) points as columns into a (4, n) matrix, P, and the entire multiplication process will be R = M * P, a result matrix R of shape (3, n) whose columns are the resulting homogeneous coordinates.

I think Gulzar's answer is correct, but more centered around rendering (i.e. camera and homogenous coordinates). I did however figure out how to do what I wanted.

import ast
import math
import matplotlib.pyplot as plt

def dot_3d(a, b):
    return (a[0]*b[0])+ (a[1]*b[1]) + (a[2]*b[2])

def minus_3d(a, b):
    return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]

def midpoint_3d(a, b):
    return [(a[0] + b[0])/2, (a[1] + b[1])/2, (a[2] + b[2])/2]

def normalize_3d(vec):
    magnitude = math.sqrt(vec[0]**2 + vec[1]**2 + vec[2]**2)
    return [vec[0]/magnitude, vec[1]/magnitude, vec[2]/magnitude]

X = 2809

A = [X, 0, 0]
B = [0, X, 0]
C = [0, 0, X]

S = set([])
for a in range(X+1):
    if int(math.sqrt(a))**2 == a:
        for b in range(X+1):
            if int(math.sqrt(b))**2 == b:
                for c in range(X+1):
                    if int(math.sqrt(c))**2 == c and a + b + c == X:
                        S.add(str([a, b, c]))
S = list(S)

origin = A
normal = normalize_3d([X/3, X/3, X/3])
ax1 = normalize_3d(minus_3d(B, A))
ax2 = normalize_3d(minus_3d(C, midpoint_3d(A, B)))

answers = []

for point_str in S:
    point = ast.literal_eval(point_str)
    x = dot_3d(ax1, minus_3d(point, origin))
    y = dot_3d(ax2, minus_3d(point, origin))
    answers.append([x, y])

plt.scatter([p[0] for p in answers], [p[1] for p in answers])
plt.xlabel('x')
plt.ylabel('y')
plt.show()

Starting 3D coordinates graphed: enter image description here

"projected" coordinates on the ABC plane: enter image description here

Related