# Reconstructing axis of pot with one shard via vertex normals

Im planning to do a reconstruction of a whole pot from one shard of it.

I've already thought of a way to do it, but I really dont know how to make it happen in code.

Theory: every shard has a certain bend to it. This bend contains two pieces of information:

• the orientation of the shard within the pot
• the diameter of the pot. You can easily see this when turning on vertex normals in edit mode. Technically, from the process of making pottery, there is a center axis in the middle of every pot. The vertex normals cross this axis, so you can see the axis clearly when turning the vertex normals on.

Problem: how do I reconstruct that axis via script? mathematically it is the intersection of the vertex normals with a thin cylinder.

Step one would be to select the vertex normals from a certain selection only, as I dont need the one facing outwards...

Test Shard

• Aug 15 '20 at 18:59
• blend-exchange.giantcowfilms.com/b/gJM8bplr Aug 15 '20 at 19:52
• @batFINGER The approach you posted may be a lot better! Ill take a closer look at it, thanks :) Aug 15 '20 at 19:54
• Thankyou for posting link. Can the pot be considered cylindrical? Have an inkling could do something with convex hull, which will have longest edges across concavity (arc) Then look for maximum distance centre point of edges to shard surface. (closest point on mesh) Aug 15 '20 at 20:06
• @batFINGER really looking forward to seeing your approach, if it goes . . As I see it atm, in large part the problem is not very Blenderish.. more like this Aug 15 '20 at 20:09

Proof of Concept

Result on single selected edge of convex hull

Further to comment, have added this as going some way to proof of concept,

Fistly here is a script that copies your object and mesh to another, goes into edit mode and converts it to a convex hull.

Select the shard and run

import bpy
bpy.ops.object.mode_set()
dupe = bpy.context.object
dupe.display_type = 'WIRE'
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.convex_hull()


after which new wire frame of the convex hull of original in edit mode with all geometry selected.

The next script goes thru the edges of the hull, finds the closest point on the mesh to its middle point, uses these to create a circle from chord as described here How can I create a mathematically correct arc/circular segment?

To visualize have added a vert at circle center and the two joining edges. As data would save as radius, centre coordinate, and normal (axis of rotation the normalized cross product of two edge vectors)

Test script, creates predicted circle "wedges" for each selected edge. Run with convex hull mesh in edit mode, edges of interest selected.

Result on all edges of convex hull

import bpy
import bmesh
from math import asin, degrees
context = bpy.context
scene = context.scene
ob = context.object
me = ob.data
bm = bmesh.from_edit_mesh(me)
shard = scene.objects.get("3D_Scherbe_Model_50K")
#edges = bm.edges[:]  # all edges
edges = [e for e in bm.edges if e.select]
#edges = [e for e in bm.select_history if isinstance(e, bmesh.types.BMEdge)]
for edge in edges:

o = (edge.verts[1].co + edge.verts[0].co) / 2

hit, loc, _, _ = shard.closest_point_on_mesh(o)

if hit:
h = (loc - o).length
if h < 0.1:
print("On surface")
continue
a = edge.calc_length() / 2
r = (a * a + h * h) / (2 * h)
if abs(a / r) > 1:
# math domain error on arcsin
print("N/A")
else:
angle = 2 * asin(a / r)
print(f"{r} {degrees(angle)}")
vc = bm.verts.new(o + r * (o - loc).normalized())
for v in edge.verts:
bm.edges.new((v, vc))
bmesh.update_edit_mesh(me)
me.update()


Notes.

• Instead of predicting a circle from the closest point to edge centre, could walk the edge and make sample points to crunch into https://meshlogic.github.io/posts/jupyter/curve-fitting/fitting-a-circle-to-cluster-of-3d-points/ and https://github.com/ndvanforeest/fit_ellipse as suggested by @RobinBetts.

• Similarly could use the generated circle estimate to test against actual mesh surface.

• Look at the normal returned from closest point on mesh.

• Narrow down the selection, is there historic data that suggests radii or wedge angle within a certain range.

• Project (closest point on mesh) equal length "subchords" of edge onto mesh, if each has same radius and angle would be a perfect match. Minimize for best fit.

• Look at the bounding box dimensions. If an edge is shorter than some fraction of minimum bbox dimension it is probably not major pot axis. Consider shaving off some percentage.

• Decimating cleaning or smoothing shard mesh in some way.

• Brilliant! I don't have so much time right now as I want to have to dig into it, but the first look is very promising! If you believe or not: reconstructing a pot is all done by hand at the moment. So basically every digital process is already an improvement to precision. Selecting edges by the user could track down the relevant "wedges" for reconstructing the axis quite effectively. Decimating and cleaning would certainly help, but also alters the original data. Aug 19 '20 at 0:35
• I may have to look for the impact by taking a shard of a pot with a known diameter, but I guess as long as the convexity of the arc doesn't change, the result should roughly be the same... or by comparing a high res mesh to a mid sized and a low poly one. If the calulated radius doesn't change much, it would make things easier to handle. I guess that depends also strongly on the size and convexity of the fragment. Aug 19 '20 at 0:36