Rekonstrukcja osi garnka z jednym odłamkiem przez normalne wierzchołków
Planuję odtworzyć cały garnek z jednego jego odłamka.
Już wymyśliłem sposób, aby to zrobić, ale naprawdę nie wiem, jak to zrobić w kodzie.
Teoria: każdy odłamek ma pewne wygięcie. To zagięcie zawiera dwie informacje:
- orientacja odłamka w puli
- średnica doniczki. Możesz to łatwo zobaczyć, włączając normalne wierzchołków w trybie edycji. Technicznie rzecz biorąc, od procesu wytwarzania ceramiki pośrodku każdego naczynia znajduje się oś środkowa. Normalne wierzchołków przecinają tę oś, dzięki czemu można wyraźnie zobaczyć oś podczas włączania normalnych wierzchołków.
Problem: jak zrekonstruować tę oś za pomocą skryptu? matematycznie jest to przecięcie wierzchołków normalnych z cienkim cylindrem.
Pierwszym krokiem byłoby wybranie normalnych wierzchołków tylko z określonego wyboru, ponieważ nie potrzebuję tego skierowanego na zewnątrz ...

Test Shard
Odpowiedzi
Dowód koncepcji

Aby skomentować, dodałem to jako dowód słuszności koncepcji,
Po pierwsze jest to skrypt, który kopiuje twój obiekt i siatkę do innego, przechodzi w tryb edycji i konwertuje go na wypukły kadłub.
Wybierz fragment i uruchom
import bpy
bpy.ops.object.mode_set()
bpy.ops.object.duplicate(linked=False)
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()
po czym nowa rama druciana wypukłego kadłuba oryginału w trybie edycji z wybraną całą geometrią.
Następny skrypt przechodzi przez krawędzie kadłuba, znajduje punkt znajdujący się najbliżej jej punktu środkowego na siatce i używa ich do utworzenia okręgu z cięciwy, jak opisano tutaj. Jak mogę utworzyć matematycznie poprawny łuk / segment kołowy?
Aby wizualizować, dodano wierzchołek w środku koła i dwie łączące się krawędzie. Ponieważ dane zostałyby zapisane jako promień, współrzędna środka i normalna (oś obrotu to znormalizowany iloczyn poprzeczny dwóch wektorów krawędzi)
Skrypt testowy tworzy przewidywane „kliny” okręgu dla każdej wybranej krawędzi. Uruchom z wypukłą siatką kadłuba w trybie edycji, z wybranymi krawędziami.

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()
Uwagi.
Zamiast przewidywać okrąg od najbliższego punktu do środka krawędzi, można chodzić po krawędzi i sprawiać, że punkty próbkowania będą https://meshlogic.github.io/posts/jupyter/curve-fitting/fitting-a-circle-to-cluster-of-3d-points/ i https://github.com/ndvanforeest/fit_ellipse zgodnie z sugestią @RobinBetts.
Podobnie można wykorzystać wygenerowane oszacowanie okręgu, aby przetestować rzeczywistą powierzchnię siatki.
Spójrz na normalny powrót z najbliższego punktu na siatce.
Zawęź wybór, czy istnieją dane historyczne, które sugerują promień lub kąt klina w określonym zakresie.
Rzut (najbliższy punkt na siatce) równej długości „podciągi” krawędzi na siatkę, jeśli każdy ma ten sam promień i kąt, byłoby idealnym dopasowaniem. Minimalizuj dla najlepszego dopasowania.
Spójrz na wymiary obwiedni. Jeśli krawędź jest krótsza niż jakiś ułamek minimalnego wymiaru bboxa, prawdopodobnie nie jest to główna oś puli. Rozważ zmniejszenie o pewien procent.
Dziesiątkowanie, czyszczenie lub wygładzanie siatki odłamkowej w jakiś sposób.