The Mesh
1 min read•1 page
The Mesh Definition
The Connected Surface: A Mesh is the most versatile way to represent complex 3D shapes. Unlike a single Polygon or a stray Mesh Face, a Mesh is a massive collection of connected vertices and faces that form a continuous surface. A Mesh is a collection of Mesh Faces. See The Mesh Face article.
python
1class Mesh:2 def __init__(self):3 self.Vertices = [] # list of Point3d4 self.Faces = [] # list of MeshFace (vertex index tuples)5 self.Normals = [] # list of Vector3d for shading
It is the industry standard for computer graphics, 3D printing, and architectural visualization. Efficiency Through Connection: The secret power of a Mesh is that multiple faces share the same vertices. If two triangles touch, they both point to a single
Point3d in a shared vertex pool.1 min read•1 page
Mesh Topology Structure
The Shared Vertex Pool: A Mesh object in code typically consists of two main lists:
Vertices: A master list of all coordinates (Point3d[]).Faces: A list of connectivity rules (MeshFace[]) that point to indices in the vertex list.
python
1class Mesh:2 def __init__(self):3 self._vertices = []4 self._faces = []56 def get_vertices(self):7 return self._vertices89 def get_faces(self):10 return self._faces
1 min read•1 page
Translate:
Translation (Move): Moving a mesh involves iterating through its entire vertex pool and adding a vector to each point. Because faces only store pointers (indices), they automatically move with the vertices.
python
1def Translate(self, vector: 'Vector3d'):2 """Translates the entire mesh by modifying the vertex pool."""3 for v in self.Vertices:4 v.X += vector.X5 v.Y += vector.Y6 v.Z += vector.Z
Move X
0.00Move Y
0.001 min read•1 page
Scale:
Scaling a mesh expands it from an origin. Often, we scale a mesh relative to its Bounding Box Center or the world origin.
python
1def Scale(self, factor: float, origin: 'Point3d'):2 """Scales the entire vertex pool relative to an origin."""3 for v in self.Vertices:4 v.X = origin.X + (v.X - origin.X) * factor5 v.Y = origin.Y + (v.Y - origin.Y) * factor6 v.Z = origin.Z + (v.Z - origin.Z) * factor
Scale Factor
1.003 min read•1 page
Rotate:
Rotation spins the entire vertex array around an axis. This is the same math used for Points and Polygons, but executed thousands of times for the entire mesh structure.
python
1import math23def Rotate(vertices: list[Point3d], angle_deg: float, axis: Vector3d, origin: Point3d) -> list[Point3d]:4 """Rotates all vertices around an axis through an origin point."""5 rad = math.radians(angle_deg)6 cos_a = math.cos(rad)7 sin_a = math.sin(rad)89 # Normalize axis vector10 axis_len = (axis.X**2 + axis.Y**2 + axis.Z**2)**0.511 ux, uy, uz = axis.X / axis_len, axis.Y / axis_len, axis.Z / axis_len1213 rotated = []14 for v in vertices:15 # Translate to origin16 x, y, z = v.X - origin.X, v.Y - origin.Y, v.Z - origin.Z1718 # Rodrigues' rotation formula19 dot = x*ux + y*uy + z*uz20 rx = x*cos_a + (uy*z - uz*y)*sin_a + ux*dot*(1 - cos_a)21 ry = y*cos_a + (uz*x - ux*z)*sin_a + uy*dot*(1 - cos_a)22 rz = z*cos_a + (ux*y - uy*x)*sin_a + uz*dot*(1 - cos_a)2324 # Translate back25 rotated.append(Point3d(rx + origin.X, ry + origin.Y, rz + origin.Z))2627 return rotated
Angle (°)
0.002 min read•1 page
Deform:
Per-Vertex Deformation: We can manipulate individual vertices of a mesh based on mathematical functions or noise to create complex, organic deformations.
python
1import math23def Deform(self, amplitude: float):4 """Deforms the mesh vertices using a wave function."""5 for v in self.Vertices:6 # Displace Z based on X and Y7 v.Z += math.sin(v.X * 5) * math.cos(v.Y * 5) * amplitude
In principle this is no different than the move, rotate, scale method. Consider it as a generalized and highly flexible approach to mesh deformation. Move Rotate and Scale apply a single transformation to all vertices, while deform can apply 1 specific transform for every individual vertex.
Consider it for each V : T(V) where T is a function that takes 1 vertex and returns a new one. Per-Vertex Deformation can manipulate individual vertices of a mesh based on mathematical functions or noise to create complex, organic deformations.
Consider it for each V : T(V) where T is a function that takes 1 vertex and returns a new one. Per-Vertex Deformation can manipulate individual vertices of a mesh based on mathematical functions or noise to create complex, organic deformations.
Amplitude
0.104 min read•1 page
Raycast:
Raycasting is the foundation of rendering, collision detection, and user interaction (like clicking on a 3D object on your screen). It calculates the intersection points between an infinite ray (defined by a start point and a direction) and the mesh faces.
python
1def RayTriangleIntersect(orig: Point3d, dir: Vector3d, v0: Point3d, v1: Point3d, v2: Point3d) -> Point3d | None:2 """Möller–Trumbore ray-triangle intersection math."""3 edge1 = Vector3d(v1.X - v0.X, v1.Y - v0.Y, v1.Z - v0.Z)4 edge2 = Vector3d(v2.X - v0.X, v2.Y - v0.Y, v2.Z - v0.Z)5 h = CrossProduct(dir, edge2)6 a = DotProduct(edge1, h)7 if -1e-6 < a < 1e-6:8 return None9 f = 1.0 / a10 s = Vector3d(orig.X - v0.X, orig.Y - v0.Y, orig.Z - v0.Z)11 u = f * DotProduct(s, h)12 if u < 0.0 or u > 1.0:13 return None14 q = CrossProduct(s, edge1)15 v = f * DotProduct(dir, q)16 if v < 0.0 or u + v > 1.0:17 return None18 t = f * DotProduct(edge2, q)19 if t > 1e-6:20 return Point3d(orig.X + dir.X * t, orig.Y + dir.Y * t, orig.Z + dir.Z * t)21 return None2223def MeshRaycast(mesh: Mesh, ray_orig: Point3d, ray_dir: Vector3d) -> list[Point3d]:24 """Intersects a ray against all faces in a mesh."""25 hits = []26 for face in mesh.Faces:27 v0 = mesh.Vertices[face.A]28 v1 = mesh.Vertices[face.B]29 v2 = mesh.Vertices[face.C]30 pt = RayTriangleIntersect(ray_orig, ray_dir, v0, v1, v2)31 if pt:32 hits.append(pt)33 return hits
Move Ray X
0.00Move Ray Y
0.003 min read•1 page
Weld:
Welding: When two faces share a vertex, they can also share a Normal (a vector pointing "out" from the surface).
python
1def Weld(vertices: list[Point3d], faces: list[tuple[int, ...]], tolerance: float = 0.001) -> tuple[list[Point3d], list[tuple[int, ...]]]:2 """Merges coincident vertices within tolerance and updates face indices.3 Enables smooth shading across face boundaries.4 """5 unique_vertices = []6 index_map = {}78 for i, v in enumerate(vertices):9 # Find if a matching vertex already exists10 match_idx = -111 for j, uv in enumerate(unique_vertices):12 dist = ((v.X - uv.X)**2 + (v.Y - uv.Y)**2 + (v.Z - uv.Z)**2)**0.513 if dist < tolerance:14 match_idx = j15 break16 if match_idx == -1:17 unique_vertices.append(v)18 index_map[i] = len(unique_vertices) - 119 else:20 index_map[i] = match_idx2122 # Rebuild faces with updated indices23 new_faces = []24 for f in faces:25 new_faces.append(tuple(index_map[idx] for idx in f))2627 return unique_vertices, new_faces
- Unwelded: Each face has its own vertices. Shading looks "faceted" or "hard-edged".
- Welded: Adjacent faces share vertices and normals. Shading looks "smooth" and organic.
Weld
3 min read•1 page
Subdivide:
Subdivision is the opposite of decimation — each level splits every face into 4 smaller faces, progressively smoothing the mesh. This is used in animation (Pixar's Catmull-Clark) and sculpting workflows to add surface detail without distorting the original shape.
python
1def SubdivideFaceMidpoint(vertices: list[Point3d], faces: list[tuple[int, int, int]]) -> tuple[list[Point3d], list[tuple[int, int, int]]]:2 """Splits each triangular face into 4 smaller triangles by finding edge midpoints."""3 new_vertices = list(vertices)4 new_faces = []5 midpoint_cache = {}67 def get_midpoint(i1, i2):8 key = tuple(sorted((i1, i2)))9 if key not in midpoint_cache:10 p1 = new_vertices[i1]11 p2 = new_vertices[i2]12 mid_pt = Point3d((p1.X + p2.X)/2.0, (p1.Y + p2.Y)/2.0, (p1.Z + p2.Z)/2.0)13 new_vertices.append(mid_pt)14 midpoint_cache[key] = len(new_vertices) - 115 return midpoint_cache[key]1617 for f in faces:18 a, b, c = f[0], f[1], f[2]19 ab = get_midpoint(a, b)20 bc = get_midpoint(b, c)21 ca = get_midpoint(c, a)2223 new_faces.append((a, ab, ca))24 new_faces.append((b, bc, ab))25 new_faces.append((c, ca, bc))26 new_faces.append((ab, bc, ca))2728 return new_vertices, new_faces
Subdivision Level
1.004 min read•1 page
Smooth:
Algorithms like Laplacian Smoothing iteratively move each vertex towards the average position of its neighbors. This gradually removes high-frequency noise and sharp features, "relaxing" the mesh into a smoother shape.
python
1def LaplacianSmooth(vertices: list[Point3d], faces: list[tuple[int, int, int]], iterations: int, lambda_factor: float = 0.5) -> list[Point3d]:2 """Applies Laplacian smoothing to the mesh vertices by averaging neighbor positions."""3 curr_vertices = list(vertices)45 # 1. Build adjacency list of vertex indices6 neighbors = {i: set() for i in range(len(vertices))}7 for f in faces:8 for idx in f:9 for other_idx in f:10 if idx != other_idx:11 neighbors[idx].add(other_idx)1213 # 2. Iterate smoothing steps14 for _ in range(iterations):15 next_vertices = []16 for i, v in enumerate(curr_vertices):17 n_indices = neighbors[i]18 if not n_indices:19 next_vertices.append(v)20 continue2122 # Compute centroid of neighbor coordinates23 sum_x = sum(curr_vertices[n].X for n in n_indices)24 sum_y = sum(curr_vertices[n].Y for n in n_indices)25 sum_z = sum(curr_vertices[n].Z for n in n_indices)26 count = len(n_indices)2728 centroid_x = sum_x / count29 centroid_y = sum_y / count30 centroid_z = sum_z / count3132 # Interpolate towards centroid33 nx = v.X + (centroid_x - v.X) * lambda_factor34 ny = v.Y + (centroid_y - v.Y) * lambda_factor35 nz = v.Z + (centroid_z - v.Z) * lambda_factor36 next_vertices.append(Point3d(nx, ny, nz))3738 curr_vertices = next_vertices3940 return curr_vertices
Smoothing Iterations
0.003 min read•1 page
Reduce:
Decimation (also called mesh reduction) reduces the face count of a mesh while preserving its overall shape. This is essential for Level-of-Detail (LOD) pipelines.
python
1def EdgeCollapse(vertices: list[Point3d], faces: list[tuple[int, int, int]], v_keep: int, v_remove: int) -> tuple[list[Point3d], list[tuple[int, int, int]]]:2"""Naive implementation"3"""Collapses the edge from v_remove to v_keep, reducing mesh complexity."""4 p_keep = vertices[v_keep]5 p_remove = vertices[v_remove]67 # Place kept vertex at midpoint of collapsed edge8 vertices[v_keep] = Point3d(9 (p_keep.X + p_remove.X) / 2.0,10 (p_keep.Y + p_remove.Y) / 2.0,11 (p_keep.Z + p_remove.Z) / 2.012 )1314 new_faces = []15 for f in faces:16 # Re-map references to collapsed vertex17 a = v_keep if f[0] == v_remove else f[0]18 b = v_keep if f[1] == v_remove else f[1]19 c = v_keep if f[2] == v_remove else f[2]2021 # Keep face only if it is not degenerate (has 3 distinct vertices)22 if a != b and b != c and c != a:23 new_faces.append((a, b, c))2425 return vertices, new_faces
Distant objects use low-poly versions to save GPU time, while close objects use the full-resolution mesh.
Target Faces
250.003 min read•1 page
Volume:
For a closed (watertight) mesh, you can compute the exact enclosed volume. This uses the divergence theorem — summing signed volumes of tetrahedra formed by each face and the origin. Essential for 3D printing material estimation and structural analysis.
python
1def ComputeFaceSignedVolume(v0: Point3d, v1: Point3d, v2: Point3d) -> float:2 """Computes signed volume of the tetrahedron formed by the face and origin."""3 cross_x = v1.Y * v2.Z - v1.Z * v2.Y4 cross_y = v1.Z * v2.X - v1.X * v2.Z5 cross_z = v1.X * v2.Y - v1.Y * v2.X67 dot = v0.X * cross_x + v0.Y * cross_y + v0.Z * cross_z8 return dot / 6.0910def ComputeMeshVolume(vertices: list[Point3d], faces: list[tuple[int, int, int]]) -> float:11 """Computes total volume of a closed watertight mesh using divergence theorem."""12 total_volume = 0.013 for f in faces:14 v0 = vertices[f[0]]15 v1 = vertices[f[1]]16 v2 = vertices[f[2]]17 total_volume += ComputeFaceSignedVolume(v0, v1, v2)18 return abs(total_volume)
Scale Factor
2.002 min read•1 page
GetNakedEdges:
Identifies topological boundaries where a mesh is open or "non-watertight".
python
1def FindNakedEdges(faces: list[tuple[int, int, int]]) -> list[tuple[int, int]]:2 """Finds all boundary (naked) edges that belong to exactly one face."""3 edge_counts = {}45 for f in faces:6 # Sort indices to treat edge (u, v) same as (v, u)7 edges = [8 tuple(sorted((f[0], f[1]))),9 tuple(sorted((f[1], f[2]))),10 tuple(sorted((f[2], f[0])))11 ]12 for e in edges:13 edge_counts[e] = edge_counts.get(e, 0) + 11415 # Boundary edges have exactly one face reference16 naked_edges = [e for e, count in edge_counts.items() if count == 1]17 return naked_edges
An edge is "Naked" if it is connected to exactly one face. By definition, a perfectly closed, solid mesh (like a sphere or a box) has zero naked edges, because every edge is shared by exactly two faces.
Detecting naked edges is the critical first step before 3D printing (which requires watertight models) or before calculating volume. If a mesh has naked edges, it's a surface, not a solid!
Detecting naked edges is the critical first step before 3D printing (which requires watertight models) or before calculating volume. If a mesh has naked edges, it's a surface, not a solid!
2 min read•1 page
Flip:
Reverses the winding order of every face, effectively turning an "inside-out" mesh back to normal.
python
1def FlipMesh(faces: list[tuple[int, int, int]], normals: list[Vector3d]) -> tuple[list[tuple[int, int, int]], list[Vector3d]]:2 """Inverts the mesh so that inside becomes outside by reversing winding and negating normals."""3 # 1. Reverse face winding order (swap index B and C)4 flipped_faces = [(f[0], f[2], f[1]) for f in faces]56 # 2. Negate normal vectors7 flipped_normals = [Vector3d(-n.X, -n.Y, -n.Z) for n in normals]89 return flipped_faces, flipped_normals
When importing 3D models from different software (like SketchUp to Rhino), meshes often arrive "inside-out". This means their surface normals are pointing into the solid interior rather than out into the world.
Inside-out meshes cause rendering bugs (they appear black or transparent due to backface culling) and break volume calculations (resulting in negative volumes). Flipping the mesh repairs this instantly.
Inside-out meshes cause rendering bugs (they appear black or transparent due to backface culling) and break volume calculations (resulting in negative volumes). Flipping the mesh repairs this instantly.
Flip Mesh
2 min read•1 page
IsClosed:
Verifies whether the mesh forms a closed, watertight boundary with no holes (closed manifold solid).
python
1def IsWatertight(faces: list[tuple[int, int, int]]) -> bool:2 """A mesh is watertight (closed) if every edge is shared by exactly 2 faces."""3 edge_counts = {}4 for f in faces:5 edges = [6 tuple(sorted((f[0], f[1]))),7 tuple(sorted((f[1], f[2]))),8 tuple(sorted((f[2], f[0])))9 ]10 for e in edges:11 edge_counts[e] = edge_counts.get(e, 0) + 11213 # Check if there are any boundary (naked) edges14 for edge, count in edge_counts.items():15 if count != 2:16 return False # Non-manifold or open boundary edge found1718 return True
For volumetric calculations, finite element analysis (FEA), and 3D printing slicing operations, the mesh must be fully watertight. Any boundary edge that connects to only one face (a naked edge) makes the mesh an open surface rather than a solid volume.
4 min read•1 page
UnifyNormals:
Synchronizes winding orders across topological neighbors to ensure all normals point consistently outward.
python
1def UnifyNormals(faces: list[tuple[int, int, int]]) -> list[tuple[int, int, int]]:2 """Traverses mesh topology to synchronize winding order (consistent orientation)."""3 # 1. Build edge adjacency map to track face connections4 edge_to_faces = {}5 for i, f in enumerate(faces):6 edges = [(f[0], f[1]), (f[1], f[2]), (f[2], f[0])]7 for e in edges:8 key = tuple(sorted(e))9 if key not in edge_to_faces:10 edge_to_faces[key] = []11 edge_to_faces[key].append((i, e))1213 # 2. Breadth-First Search (BFS) to orient winding consistently14 visited = [False] * len(faces)15 queue = [0] # start with first face16 visited[0] = True1718 while queue:19 curr_idx = queue.pop(0)20 curr_face = faces[curr_idx]21 curr_edges = [(curr_face[0], curr_face[1]), (curr_face[1], curr_face[2]), (curr_face[2], curr_face[0])]2223 for e in curr_edges:24 key = tuple(sorted(e))25 neighbors = edge_to_faces.get(key, [])26 for n_idx, n_edge in neighbors:27 if visited[n_idx]:28 continue2930 # If neighbor shares the edge, they must traverse it in opposite directions31 # If they traverse in same direction, neighbor winding is inverted and must flip32 n_face = faces[n_idx]33 if e[0] == n_edge[0]: # same direction traversal34 faces[n_idx] = (n_face[0], n_face[2], n_face[1]) # swap B and C index3536 visited[n_idx] = True37 queue.append(n_idx)3839 return faces
If some faces are wound clockwise and others counter-clockwise, their normal vectors will point in opposite directions, causing shading artifacts, rendering glitches, and volumetric check failures. Unifying normals aligns neighbors to run in consistent directions.
Unify Normals
2 min read•1 page
ClosestVertex:
Finding the closest vertex involves iterating over the entire vertex pool and calculating the distance to the test point. It completely ignores faces and edges, and guarantees the result is one of the existing control points.
python
1def ClosestVertex(test_pt: Point3d, vertices: list[Point3d]) -> Point3d:2 """Finds the closest vertex in a mesh to a given test point."""3 min_dist = float('inf')4 best_pt = None56 for pt in vertices:7 dist = ((test_pt.X - pt.X)**2 + (test_pt.Y - pt.Y)**2 + (test_pt.Z - pt.Z)**2)**0.58 if dist < min_dist:9 min_dist = dist10 best_pt = pt1112 return best_pt
Search Pt X
4.00Search Pt Y
4.002 min read•1 page
ClosestFace:
Finding the closest face typically implies finding the face whose geometric center (centroid) is closest to the test point. This doesn't guarantee the absolute closest point on the mesh surface, but it's computationally faster.
python
1def ClosestFaceCenter(test_pt: Point3d, mesh: Mesh) -> Point3d:2 """Finds the closest face center in a mesh to a given test point."""3 min_dist = float('inf')4 best_pt = None56 for face in mesh.Faces:7 a = mesh.Vertices[face.A]8 b = mesh.Vertices[face.B]9 c = mesh.Vertices[face.C]1011 center = Point3d(12 (a.X + b.X + c.X) / 3.0,13 (a.Y + b.Y + c.Y) / 3.0,14 (a.Z + b.Z + c.Z) / 3.015 )1617 dist = ((test_pt.X - center.X)**2 + (test_pt.Y - center.Y)**2 + (test_pt.Z - center.Z)**2)**0.518 if dist < min_dist:19 min_dist = dist20 best_pt = center2122 return best_pt
Search Pt X
4.00Search Pt Y
4.003 min read•1 page
ClosestEdge:
Finding the closest point on the mesh edge network involves iterating over every edge and projecting the test point onto the edge's line segment. The resulting point may lie directly on a vertex or anywhere along the edge segment.
python
1def ClosestPointOnEdge(test_pt: Point3d, edges: list[tuple[Point3d, Point3d]]) -> Point3d:2 """Finds the closest point on the mesh edge network to a test point."""3 min_dist = float('inf')4 best_pt = None56 for a, b in edges:7 ab = Vector3d(b.X - a.X, b.Y - a.Y, b.Z - a.Z)8 ap = Vector3d(test_pt.X - a.X, test_pt.Y - a.Y, test_pt.Z - a.Z)910 ab_len_sq = ab.X**2 + ab.Y**2 + ab.Z**211 if ab_len_sq == 0:12 continue1314 t = DotProduct(ap, ab) / ab_len_sq15 t = max(0.0, min(1.0, t))1617 pt = Point3d(a.X + t*ab.X, a.Y + t*ab.Y, a.Z + t*ab.Z)18 dist = ((test_pt.X - pt.X)**2 + (test_pt.Y - pt.Y)**2 + (test_pt.Z - pt.Z)**2)**0.51920 if dist < min_dist:21 min_dist = dist22 best_pt = pt2324 return best_pt
Search Pt X
4.00Search Pt Y
4.008 min read•2 pages
ClosestPoint:
Finding the closest point on a mesh requires projecting a test point onto every triangle to find the absolute minimum distance. The resulting nearest point might lie exactly on a vertex, along an edge, or flat on the interior of a face.
python
1def ClosestPointOnTriangle(p: Point3d, a: Point3d, b: Point3d, c: Point3d) -> Point3d:2 """Finds the closest point on a triangle ABC to point P using vector projection."""3 ab = Vector3d(b.X - a.X, b.Y - a.Y, b.Z - a.Z)4 ac = Vector3d(c.X - a.X, c.Y - a.Y, c.Z - a.Z)5 ap = Vector3d(p.X - a.X, p.Y - a.Y, p.Z - a.Z)67 d1 = DotProduct(ab, ap)8 d2 = DotProduct(ac, ap)9 if d1 <= 0.0 and d2 <= 0.0:10 return a1112 bp = Vector3d(p.X - b.X, p.Y - b.Y, p.Z - b.Z)13 d3 = DotProduct(ab, bp)14 d4 = DotProduct(ac, bp)15 if d3 >= 0.0 and d4 <= d3:16 return b1718 vc = d1 * d4 - d3 * d219 if vc <= 0.0 and d1 >= 0.0 and d3 <= 0.0:20 v = d1 / (d1 - d3)21 return Point3d(a.X + ab.X * v, a.Y + ab.Y * v, a.Z + ab.Z * v)2223 cp = Vector3d(p.X - c.X, p.Y - c.Y, p.Z - c.Z)24 d5 = DotProduct(ab, cp)25 d6 = DotProduct(ac, cp)26 if d6 >= 0.0 and d5 <= d6:27 return c2829 vb = d5 * d2 - d1 * d630 if vb <= 0.0 and d2 >= 0.0 and d6 <= 0.0:31 w = d2 / (d2 - d6)32 return Point3d(a.X + ac.X * w, a.Y + ac.Y * w, a.Z + ac.Z * w)3334 va = d3 * d6 - d5 * d435 if va <= 0.0 and (d4 - d3) >= 0.0 and (d5 - d6) >= 0.0:36 w = (d4 - d3) / ((d4 - d3) + (d5 - d6))37 return Point3d(b.X + (c.X - b.X) * w, b.Y + (c.Y - b.Y) * w, b.Z + (c.Z - b.Z) * w)3839 denom = 1.0 / (va + vb + vc)40 v = vb * denom41 w = vc * denom42 return Point3d(a.X + ab.X * v + ac.X * w, a.Y + ab.Y * v + ac.X * w, a.Z + ab.Z * v + ac.Z * w)4344def ClosestPoint(mesh: Mesh, test_pt: Point3d) -> Point3d:45 """Finds the closest location on the entire mesh surface."""46 min_dist = float('inf')47 best_pt = None4849 for face in mesh.Faces:50 a = mesh.Vertices[face.A]51 b = mesh.Vertices[face.B]52 c = mesh.Vertices[face.C]53 pt = ClosestPointOnTriangle(test_pt, a, b, c)54 dist = ((test_pt.X - pt.X)**2 + (test_pt.Y - pt.Y)**2 + (test_pt.Z - pt.Z)**2)**0.555 if dist < min_dist:56 min_dist = dist57 best_pt = pt5859 return best_pt
Search Pt X
4.00Search Pt Y
4.00