Gaussian Curvature
Curvature Types:
1# Gaussian Curvature Theory2def understand_curvature(K):3 """K = k1 * k2 (the two principal curvatures)"""45 if K > 0:6 return "Positive (Synclastic): Like a Sphere. Bends same way in all directions."7 elif K < 0:8 return "Negative (Anticlastic): Like a Saddle. Bends up in one direction, down in another."9 else:10 return "Zero (Developable): Like a Cylinder or flat plane. Unrolls flat without tearing."
In Differential Geometry, we classify the shape of a surface based on how it bends.Gaussian Curvature (K) is an intrinsic property, meaning it doesn't change even if you bend the surface (without stretching it).
Discrete Differential Geometry:
1# Finding the 1-Ring Neighborhood2def get_vertex_star(mesh, vertex_id):3 """Returns all faces and vertices immediately connected to a vertex."""45 # We query the topology graph6 connected_faces = mesh.topology.get_faces_at_vertex(vertex_id)7 connected_vertices = mesh.topology.get_neighbors(vertex_id)89 return connected_faces, connected_vertices
In a continuous math formula, curvature is measured at an infinitely small point. But in a discrete Triangle Mesh, curvature can only be approximated by looking at a vertex and its immediate neighbors.
Area Weighting:
1# Voronoi Area of a Vertex2def calculate_mixed_voronoi_area(vertex_id, star_faces):3 """Calculates the surface area 'belonging' to a single vertex."""45 total_area = 0.067 for face in star_faces:8 # A simple approximation (Barycentric area) is 1/3 of each triangle's area9 tri_area = calculate_triangle_area(face)1011 # In Meyer's true algorithm, we use the Mixed Voronoi Area12 # which accounts for obtuse (wide) triangles, but 1/3 is often good enough!13 total_area += (tri_area / 3.0)1415 return total_area
Because curvature is a measure of how bending changes over an area, we need to know exactly how much surface area "belongs" to our central vertex.
The 360 Rule:
1# Calculating Angle Deficit2def calculate_angle_deficit(vertex_id, star_faces):3 """How much a vertex behaves like a cone vs a saddle."""45 # Start with 2*PI (a completely flat, 360 degree circle)6 angle_sum = 2.0 * math.pi78 for face in star_faces:9 # Find the angle of this specific triangle at the central vertex10 theta = calculate_triangle_angle(face, center=vertex_id)1112 # Subtract it from our total13 angle_sum -= theta1415 # The remainder is the 'Angle Deficit'16 return angle_sum
How do we know if a vertex is flat, peaked, or saddle-shaped just by looking at its triangles? We use the Angle Deficit.
Mesh Independence:
1# Calculating Discrete Gaussian Curvature2def get_gaussian_curvature(vertex_id, mesh):3 """Combines Angle Deficit with Voronoi Area."""45 star_faces = mesh.topology.get_faces(vertex_id)67 # 1. Get the raw angular deficit8 angle_deficit = calculate_angle_deficit(vertex_id, star_faces)910 # 2. Get the surface area belonging to this vertex11 voronoi_area = calculate_mixed_voronoi_area(vertex_id, star_faces)1213 # 3. Normalize!14 # Without this, a densely tessellated sphere would seem to have15 # less curvature per-vertex than a low-poly sphere.16 K = angle_deficit / voronoi_area1718 return K
We have the Angle Deficit (the raw bending amount) and the Voronoi Area (the size of the neighborhood). To get the final Gaussian Curvature (K), we simply divide the Deficit by the Area.
Color Mapping:
K value to a 0.0 - 1.0 percentage. 3. Map that percentage to a color gradient. Usually:- Red: High Positive (Peaks)
- Green/Grey: Zero (Flat)
- Blue: High Negative (Saddles/Valleys)
1# Vertex Color Mapping2def apply_curvature_colors(mesh, k_array):3 """Maps numerical curvature to an RGB gradient."""45 # K can be anything from -100 to +100 depending on scale.6 # We need to map this to a 0.0 to 1.0 color gradient.78 k_min = min(k_array)9 k_max = max(k_array)1011 for vertex_id, K in enumerate(k_array):12 # Normalize K to a 0-1 range based on the mesh extremes13 normalized_k = (K - k_min) / (k_max - k_min)1415 # Look up color in a gradient map (e.g. Blue -> Green -> Red)16 color = sample_gradient(normalized_k)1718 mesh.vertices[vertex_id].color = color
Once we calculate Gaussian Curvature K for every single vertex on a mesh, we have an array of numbers. To make this data useful to humans, we map those numbers to Vertex Colors.
Visual Diagnostics:
1# Complete Curvature Pipeline2def analyze_surface_curvature(mesh):3 """Full discrete differential geometry analysis."""45 curvature_data = []67 for vertex in mesh.vertices:8 # 1. Topological Analysis (1-Ring)9 star = get_vertex_star(mesh, vertex.id)1011 # 2. Geometric Analysis12 deficit = calculate_angle_deficit(vertex.id, star)13 area = calculate_mixed_voronoi_area(vertex.id, star)1415 # 3. Normalization16 K = deficit / area17 curvature_data.append(K)1819 # 4. Rendering20 apply_curvature_colors(mesh, curvature_data)2122 return mesh
In advanced 3D modeling and CAD pipelines, Curvature Analysis is used constantly. Industrial designers use it to ensure surfaces are smooth without hidden inflection flaws, while 3D printing tools use it to identify sharp peaks or fragile regions.
Related Concepts
Half-edge mesh navigation, local edge flips, splits, and decimation collapses.
Volume, mass properties, and surface curvature.
Exact polyhedral surface area via cross-product magnitudes and enclosed volume via signed tetrahedral summation.