Repository navigation
Releases: Krateian/Sutura
Release list
Sutura v0.9.1
Sutura v0.9.1
A small maintenance release. It removes two sources of run-to-run variation from the deterministic tiers, eliminates a geometry step that could make the shell analysis crawl or hang, and trims dependencies.
Fewer sources of run-to-run variation
Before this release, two things could change a result without you changing anything:
- Graft (the shell-wrap tier that closes severe damage) picked its resolution partly from how much free RAM the machine had, so the same model could come out slightly different on a busy machine or after other work had claimed memory. Graft now chooses its grid only from the input and the intensity preset, and if that grid does not fit it falls back once to the smaller "Balanced" grid and says so, instead of quietly shrinking the model or refusing.
- The fTetWild last-resort tier decided whether to try a second pass based on how long the first pass had taken. That decision is now made only from whether the first result was good enough, not from the clock.
The practical effect: Graft's result no longer depends on how much free RAM the machine has or on CPU speed and load, and the fTetWild retry decision no longer depends on the clock.
Faster on a hard mesh
A step in the shell analysis that triangulates the mesh around self-intersections was not converging: each pass could roughly double the number of triangles and keep going. On the reference hard mesh it could take several seconds and on a denser one it could grow toward hundreds of millions of triangles and effectively hang. It now finishes the same geometry directly.
On the integration 8-mesh smoke set, total CLI repair time fell from 171.7 s to 146.2 s:
- the reference hard mesh (
thingi10k_100045): 7.49 s → 1.44 s end to end; thingi10k_40886: 62.4 s → 37.4 s.
Interleaved re-measurement confirmed no regression on the other meshes, with medians improving as well: artec_bovine-heart 6.88 s → 5.57 s and thingi10k_46012 37.1 s → 35.5 s.
Fewer dependencies
psutil and pyrobust-predicates are no longer needed, making the installation lighter. In addition, an optional set of native Rust replacements exists behind SUTURA_NATIVE_* environment flags, off by default.
What you will see in the GUI
The repair log now states plainly when Graft used the smaller "Balanced" grid, when it was skipped for low memory, and when Graft or fTetWild was stopped for time — in the last two cases the earlier stage result is kept, so nothing is lost.
Smaller change
Tamponade's final safety check is now much cheaper to run (it measures only when it might need to, about 0.84 s → 0.14 s on one reference mesh) with no change to the output.
Known limitations
fTetWild (the last-resort tier) is still not byte-reproducible between runs.
Sutura v0.9.0
Sutura v0.9.0
Sutura v0.9.0 adds a way to seal holes from the inside, makes the default hole
filler try harder before it gives up, and quietly trims two dependencies.
Tamponade and its Stent candidate are on by default, following the standing rule
that improvements are opt-out: turn them off with --no-tamponade (env
SUTURA_TAMPONADE=0) or the GUI checkbox. Flap also now tries harder — a
boundary loop it used to give up on tries alternative fills, one at a time. A
loop Flap already filled is byte-identical and costs nothing extra.
What is new
-
Tamponade — a "fill from the inside" plug (repair method #17).
Right after the Stage 1 clean-up, before Flap and the generic hole closing,
Tamponade fills each open hole from inside, like lava (holes it skips get a
second chance after Flap, before the deep Graft/fTetWild tiers): the plug is sealed at the narrowest point
right at the shell, and the surrounding healthy surface is never touched (the
original triangles are kept exactly as they were). Trapped folds inside the
part are melted out one thin layer at a time, and any layer that would make
things worse is undone. It runs by default; turn it off with--no-tamponade
(envSUTURA_TAMPONADE=0) or the GUI checkbox Tamponade (fill holes from
inside). -
Stent, and multi-Stent. Inside Tamponade, if a loop's normal plug is
rejected, Sutura now inflates a plug inward from the rim instead — called a
Stent. It grows from inside the part and freezes the moment it touches the
shell, so it can never push outside. A large hole that one Stent cannot seal is
split into several sub-loops, one Stent per piece, sharing a seam so the result
stays a single connected solid. Stent has no separate switch; it runs only when
Tamponade is on. If you want Tamponade without it, setSUTURA_TAMP_STENT=0.
(This is not the same as method #8 Balloon, which rebuilds a whole surface with
Poisson reconstruction.) -
Clear, strict acceptance rules for every plug. A Tamponade plug is kept
only if it: does not leak outside the part beyond a tiny tolerance; adds no new
holes or bad edges when the file is re-opened from disk; does not lay an
opposite-facing double wall over more than 20% of its area; stays connected to
the main shell and adds no separate part; and keeps at least 99% of the
pre-tier faces byte-for-byte (the input faces carried through verbatim).
Self-intersections are reported only — a slicer unions overlapping volumes, so
they never block a seal. -
Graft refuses a result that covers too little of the input. A Graft
candidate that misses too much of the input surface is now refused, and the
repair falls through to the next deep tier instead of adopting it. -
A final safety net for Tamponade. If an adopted Tamponade result collapses
or leaks, the repair is re-run without Tamponade, so a bad plug can never make
the output worse. -
Flap tries harder before giving up (on by default). Each boundary loop
still gets the same patch as before first, so a loop that works today is
unchanged and costs nothing extra. Only when that patch is rejected does the
loop now try a few alternative fills, one at a time, keeping the first that
passes the same safety checks. The extra tries are charged against Flap's
existing time budget, so this cannot make a repair run past its limit. Opt out
withSUTURA_FLAP_SELECT=0. -
A memory/time guard on the Scaffold resample (method #10). On meshes with
long, skinny triangle fans the resample filter could slow to a crawl and eat
all the memory, killing the whole repair. It now runs in a child process under
a time limit (20 s,SUTURA_PROXY_RESAMPLE_TIMEOUT) and a memory cap (2 GB,
SUTURA_PROXY_RESAMPLE_MAX_RSS_MB), and falls through to the existing fallback
as soon as either is reached. Output is unchanged whenever the resample
finishes in time. -
Smaller install, faster clean-up. Phase 1 removes two dependencies
(psutilandpyrobust-predicates, replaced by the standard library and the
Rust core), saving about 2.1 MB. Phase 2a/2b move more of the Stage 1
mesh-cleaning work (duplicate/loose faces and vertices, vertex welding,
connected-component removal, face flipping) onto the Rust kernel, each with a
pure-NumPy fallback that produces bit-for-bit identical results.
Screenshots
Under the hood
-
Native self-intersection detection (off by default). The self-intersection
count can now come from Sutura's own Rust kernel instead of PyMeshLab. It is
behindSUTURA_NATIVE_SI=1and off by default because the count is not
byte-identical to PyMeshLab's; it is an evaluation switch with no CLI flag or
GUI control, so the CLI and the GUI always behave the same. -
The README's license-rationale paragraph was moved into the
## License
section (text unchanged).
Notes
- The Rust extension (
sutura_geom) must providesutura_geom.tamponadefor
method #17; there is no NumPy fallback, and the method reports itself
unavailable when the extension lacks it. - Every user-facing entry point (CLI, GUI, file-manager menu, OrcaSlicer
plugin) runs Tamponade (and its Stent candidate) by default; the Flap
per-loop selection is likewise on by default. Disable Tamponade with
--no-tamponade/SUTURA_TAMPONADE=0/ the GUI checkbox. Every other new
tier is opt-in or adopted only when it is not worse.
Known limitations
- On most real files the later repair stages already close tiny holes, so Stent
mostly matters inside Tamponade. - Graft output can vary slightly between runs depending on how much free RAM is
available (the shape stays valid); a fix is planned for 0.9.1.
v0.8.1
Sutura v0.8.1 — Faster topology, cleaner solids
The short version: Sutura v0.8.1 speeds up mesh repair by moving repetitive triangle and vertex welding into a native Rust kernel, shaving 4% to 29% off repair times while producing bit-for-bit identical geometry for the accelerated operations. A post-union cleanup step also removes microscopic scrap slivers from solid rebuilds, so single-body models open as exactly one part in the slicer without disturbing genuine multi-part assemblies.
What changed, in plain words
Faster core topology (Rust kernel). During repair, Sutura constantly welds vertices, checks for duplicate triangles, and counts shared edges. These operations now run in a native Rust kernel (sutura_geom) instead of pure Python/numpy loops. It is completely automatic and requires no configuration. If the prebuilt Rust extension is not installed, Sutura falls back to the pure Python path transparently. The output of the accelerated operations is bit-for-bit identical to previous releases; the separate sliver cleanup described below is the only change in this release that alters geometry, and only on the two affected models.
Cleaner solid output: post-union micro-sliver cleanup. In Stage 2, when dozens or hundreds of overlapping shells are merged into a solid using boolean operations, the intersection cuts can occasionally cleave off detached, microscopic slivers (often just 6 triangles with virtually zero volume). Previously, these stray slivers escaped into the output file, causing slicers like OrcaSlicer to report "2 parts" or "3 parts" on what should be a single print. A second debris filter now inspects the components immediately after the boolean union and prunes isolated micro-slivers with zero printable volume (
Defect-report fix for non-manifold face indices. The defect scanner's non-manifold region detector had a half-edge mapping defect where block-stacked edges were mapped with faces_idx) to attribute bad edges to the wrong neighbouring triangles in the JSON report and the GUI heatmap. The fix aligns the face mapping so reported defect regions point precisely to the culprit faces. Measured effect on the 41-model corpus: the correction changes the defects report on 8 models, 7 of which also show the corrected counts in the flap/p_weld diagnostic metadata; no repair decision, output geometry, watertight verdict, part count or self-intersection count changes.
Documentation and Turkish naming. The test suite count in the documentation has been updated to reflect the full test suite (63 Python test modules and 92 Rust unit tests). In the Turkish documentation, GUI options, and CLI hints, Dressing (method #16) is now consistently referred to as "Pansuman (Dressing)" to clarify its medical metaphor as a protective, contour-wrapping bandage rather than clothing.
What we measured
-
Faster wall-clock repairs: In interleaved, alternating benchmark runs across 5 representative models, the Rust topology kernel delivered measurable end-to-end speedups:
-
thingi10k_1038441(dense self-intersections): 14.79s → 10.45s (+29.3% faster) -
artec_copper-key(smooth curved scan): 3.93s → 3.48s (+11.5% faster) -
thingi10k_100281(heavy self-intersections): 3.77s → 3.34s (+11.4% faster) -
thingi10k_224108(closed shell, Flap + P-HONEST): 5.06s → 4.62s (+8.7% faster) -
thingi10k_145065(non-manifold vertices): 2.64s → 2.54s (+4.0% faster)
-
-
Bit-for-bit geometric identity (topology-kernel benchmark): Across the 41-model regression corpus, 41 out of 41 models exit 0 and achieve
category: watertight. 40 out of 41 produce bit-for-bit identical SHA256 file hashes between the Python oracle and the Rust topology kernel. The single differing mesh (thingi10k_100827) triggered the external fTetWild engine, which is known to produce nondeterministic tetrahedralizations across runs. The sliver cleanup below separately changes the geometry of the two models it repairs. -
Micro-sliver removal:
- On an ornate frame scan (~400k triangles), OrcaSlicer previously reported 2 parts due to a detached 6-face sliver (
$V \approx 2.15 \times 10^{-5}\text{ mm}^3$ ). With post-union filtering, the model opens cleanly as 1 part, manifold, 0 open edges, with watertightness intact and exact self-intersections unchanged at 3005. - On
thingi10k_1038441, the slicer part count dropped from 3 to 1 and the manifold3d shell count from 11 to 1 (10 boolean micro-slivers pruned), while exact self-intersections fell from 283 to 268. -
Zero false positives on multi-solid assemblies: Legitimate multi-part models remain untouched (
thingi10k_1038439preserves all 3 bodies,thingi10k_228302preserves all 8 solid cubes).
- On an ornate frame scan (~400k triangles), OrcaSlicer previously reported 2 parts due to a detached 6-face sliver (
Defaults at a glance
| Feature | Default | Switch / Option |
|---|---|---|
| Topology kernel | Rust (sutura_geom) |
SUTURA_TOPOLOGY=python (forces Python oracle) |
| Post-union micro-sliver cleanup | on | Automatic inside Stage 2 solid rebuild |
| Flap surface hole fill | on | --no-flap, SUTURA_FLAP=0 |
| Self-intersections | reported, not a failure | --si-mode repair / off |
| Dressing | off, suggested only | --experimental-dressing |
Assets
Sutura-x86_64.AppImage: LinuxSutura-v0.8.1.dmg: macOS (unsigned; first launch: right-click → Open)sutura_geom-*.whl+sutura_geom-SHA256SUMS: prebuilt geometry extension including the new topology kernel
Full technical details: CHANGELOG.md
Sutura v0.8.1 — Daha hızlı topoloji, daha temiz katılar
Kısaca: Sutura v0.8.1, sık tekrarlanan üçgen ve köşe kaynatma işlemlerini yerel bir Rust çekirdeğine taşıyarak onarım sürelerini %4 ila %29 oranında hızlandırıyor; hızlandırılan işlemlerde çıktı önceki sürümlerle bayt bayt aynı kalıyor. Katı oluşturma sonrasına eklenen temizlik adımı ise dilimleyicilerde tek parça olması gereken modellerin fazladan parça gibi görünmesine yol açan mikroskobik kıymıkları temizliyor ve gerçek çok parçalı montajlara hiç dokunmuyor.
Neler değişti, sade anlatım
Daha hızlı çekirdek topoloji (Rust motoru). Sutura onarım boyunca sürekli köşe noktalarını birleştirir, mükerrer üçgenleri eler ve ortak kenarları sayar. Bu işlemler artık saf Python/numpy döngüleri yerine doğrudan yerel Rust çekirdeğinde (sutura_geom) yürütülüyor. Tamamen otomatik çalışır; herhangi bir ayar yapman gerekmez. Derlenmiş Rust eklentisi bulunmayan ortamlarda Sutura sessizce saf Python yoluna geçer. Hızlandırılan işlemlerin çıktısı önceki sürümlerle bayt bayt aynıdır; bu sürümde geometriyi değiştiren tek adım, aşağıda açıklanan ve yalnızca iki modeli etkileyen kıymık temizliğidir.
Daha temiz katı model: birleşim sonrası mikroskobik kıymık temizliği. Aşama 2'de, onlarca veya yüzlerce kesişen kabuk boole işlemleriyle birleştirilirken, kesişim sınırları bazen neredeyse sıfır hacimli mikroskobik kıymıklar (genellikle 6 üçgenlik kopuk parçacıklar) koparabilir. Eskiden bu artık parçacıklar çıktı dosyasına sızıyor ve OrcaSlicer gibi dilimleyicilerin aslında tek parça olması gereken baskıyı "2 parça" veya "3 parça" olarak görmesine yol açıyordu. Boole birleşiminin hemen ardına eklenen ikinci bir çöp filtresi, bu hacimsiz (
Non-manifold yüzey indeksleri için hata düzeltmesi. Hata tarayıcısındaki manifold olmayan bölge tespit edicide bir kenar-yüz eşleme hatası bulundu: blok olarak dizilen kenarlar defects raporunu 8 modelde değiştirir ve bu modellerin 7'sinde düzeltilmiş sayılar flap/p_weld tanılama üstverisinde de görünür; hiçbir onarım kararı, çıktı geometrisi, su geçirmezlik hükmü, parça sayısı veya kendisiyle kesişme sayısı değişmez.
Dokümantasyon ve Türkçe terim tutarlılığı. Dokümanlardaki test sayıları güncellenerek tam test paketini (63 Python test modülü ve 92 Rust birim testi) yansıtacak şekilde netleştirildi. Türkçe dokümantasyonda, arayüz seçeneklerinde ve terminal ipuçlarında Dressing (yöntem #16), kıyafet çağrışımını önlemek ve yara bakımındaki koruyucu sargı işlevini tam yansıtmak amacıyla tutarlı olarak "Pansuman (Dressing)" olarak adlandırıldı.
Ölçtüklerimiz
- Daha hızlı onarım süreleri: 5 temsilci model üzerinde dönüşümlü olarak yapılan hız ölçümlerinde, Rust topoloji çekirdeği uçtan uca belirgin hızlanmalar sağladı:
thingi10k_1038441(yoğun kendisiyle kesişme): 14,79 sn → 10,45 sn (%29,3 daha hızlı)artec_copper-key(yumuşak kavisli tarama): 3,93 sn → 3,48 sn (%11,5 daha hızlı)thingi10k_100281(ağır kesişmeler): 3,77 sn → 3,34 sn (%11,4 daha hızlı)thingi10k_224108(kapalı kabuk, Flap + P-HONEST): 5,06 sn → 4,62 sn (%8,7 daha hızlı)thingi10k_145065(manifold olmayan köşeler): 2,64 sn → 2,54 sn (%4,0 daha hızlı)
- Bayt bayt geometrik eşitlik (topoloji çekirdeği ölçümü): 41 modellik test külliyatında 41 modelin tamamı hata kodu vermeden (rc=0) kapalı ve su geçirmez (watertight) çıktı. 41 modelin 40'ında SHA256 dosya özeti Python ve Rust motorları arasında bayt bayt aynı kaldı. Farklı çıkan tek model olan `th...
v0.8.0
Sutura v0.8.0 — Flap: holes filled the way the surface wants to go
The short version: Sutura now fills holes by continuing the surface around
them instead of putting a flat lid on top. Curved scans get curved patches,
your original triangles stay where they were, and badly damaged files still fall
back to the proven repair steps. It is on by default; you do not need to change
anything.
What changed, in plain words
Flap: the new hole filler (on by default). A classic hole fill closes a hole
with a flat lid, which leaves dents and flat spots on curved surfaces. Flap works
more like brushing liquid primer or epoxy over a gap: the patch leaves the rim
with the same slope as the surface around it and flows smoothly across, so a hole
in a sphere gets a piece of sphere, not a coin. Only the patch is new; the
triangles you already had are not moved. If Flap cannot fill a hole safely it
hands it to the old filler, so a file is never worse with Flap than without it.
Turn it off with --no-flap or the Flap surface hole fill checkbox.
How a repair runs now:
your file ─► Flap ─► Stage 1 clean-up ─► (still broken?) Graft ─► Stage 2 solid ─► repaired copy
- Flap fills holes along the surface.
- Stage 1 (PyMeshLab) removes broken triangles, untangles bad edges and closes what is left.
- Graft steps in only when the damage is serious: it builds a fresh shell over the
damaged areas and grafts it onto the healthy original surface, like a skin graft, so
engraving and ornament survive. - Stage 2 (manifold3d) turns the result into one closed, printable solid.
After every step Sutura re-counts holes and bad edges as if the file had been
re-opened from disk and throws away any step that made things worse. Your
original file is never changed.
What we measured
- On our 41-model test set (real scans and Thingi10K models), all 41 come out
closed with Flap on by default. Flap stepped in on 13 of them and did not
make a single one worse (no lost watertightness, no extra parts). - On one damaged scan (thingi10k_1038441) the largest change to the surface
dropped from 4.11 mm to 0.60 mm, because the holes are now filled along the
surface instead of being bridged. - On a private, heavily damaged ornamental frame scan (220 shells, thousands of
open edges), OrcaSlicer now reports the repaired file clean: 0 open edges,
manifold. Fine ornament is visually unchanged. - Flap's core runs in Rust: the Flap step for the whole 41-model set takes about
7 seconds. If the Rust extension is missing, an identical Python version is
used. - Huge scans no longer hang. Graft now has a size and time limit; six dense
scans (2–6 million triangles) that used to run past 10 minutes now finish in
3–6 minutes with an honest "too large, skipped" note in the report.
Also new
- Self-intersection reporting (
--si-mode). Small self-intersections that
slicers ignore are now reported but no longer count as a failed repair
(defaultreport).--si-mode repairbrings back the strict behaviour,off
skips the check. - Dressing (method #16), opt-in. A "dip-coat" repair that always produces a
closed model but can soften fine detail. It is off by default; when every
other step fails, Sutura suggests it (CLI hint, GUI "⚠ Try Dressing" button,
and now also in the OrcaSlicer plugin panel) and you decide. - Fewer leftover scraps. Paper-thin, zero-volume sheets are removed before the
final solid is built, which cuts self-intersections and stray parts. - OrcaSlicer plugin ships the new engine and shows the Dressing suggestion.
- Docs: README (English and Turkish) has a new plain-language "How Sutura
repairs a mesh" section; the pipeline is now described as staged rather than
"two-stage", since there are more than two steps.
Defaults at a glance
| Feature | Default | Switch |
|---|---|---|
| Flap surface hole fill | on | --no-flap, SUTURA_FLAP=0 |
| Self-intersections | reported, not a failure | --si-mode repair / off |
| Graft size/time limit | by intensity preset | Extreme = no face limit |
| Dressing | off, suggested only | --experimental-dressing |
Assets
Sutura-x86_64.AppImage: LinuxSutura-v0.8.0.dmg: macOS (unsigned; first launch: right-click → Open)sutura_geom-*.whl+sutura_geom-SHA256SUMS: prebuilt geometry extension, picked up automatically by the installers
Full technical details: CHANGELOG.md
Sutura v0.8.0 — Flap: delikler yüzeyin gittiği yöne doğru dolduruluyor
Kısaca: Sutura artık delikleri üstüne düz bir kapak koyarak değil,
çevresindeki yüzeyi devam ettirerek dolduruyor. Kavisli taramalar kavisli yama
alıyor, orijinal üçgenlerin yerinde kalıyor ve çok bozuk dosyalar yine kanıtlanmış
onarım adımlarına düşüyor. Varsayılan açık; hiçbir şeyi değiştirmen gerekmiyor.
Neler değişti, sade anlatım
Flap: yeni delik doldurucu (varsayılan açık). Klasik delik doldurma deliği
düz bir kapakla kapatır; bu da kavisli yüzeylerde çukur ve düz lekeler bırakır.
Flap ise bir boşluğun üstüne sıvı astar ya da epoksi sürmek gibi çalışır: yama,
kenardan çevresindeki yüzeyle aynı eğimle çıkar ve deliğin üstünden yumuşakça
akar; böylece bir küredeki delik madeni para gibi düz bir kapak değil, kürenin bir
parçasını alır. Yalnızca yama yenidir; zaten var olan üçgenlerin yerinden
oynamaz. Flap bir deliği güvenle dolduramıyorsa onu eski doldurucuya bırakır;
yani bir dosya Flap ile asla Flap'siz halinden kötü olmaz. Kapatmak için
--no-flap ya da Flap yüzey delik doldurma kutusu.
Onarım artık şöyle ilerliyor:
dosyan ─► Flap ─► Aşama 1 temizlik ─► (hâlâ bozuk mu?) Graft ─► Aşama 2 katı ─► onarılmış kopya
- Flap delikleri yüzeyi sürdürerek doldurur.
- Aşama 1 (PyMeshLab) bozuk üçgenleri siler, hatalı kenarları çözer, kalanları kapatır.
- Graft yalnızca hasar ciddiyse devreye girer: hasarlı bölgelerin üstüne yeni bir
kabuk kurar ve bunu sağlam orijinal yüzeye deri nakli gibi diker; oyma ve süsleme
kaybolmaz. - Aşama 2 (manifold3d) sonucu tek parça, kapalı, basılabilir bir katıya çevirir.
Sutura her adımdan sonra delikleri ve hatalı kenarları, dosya diskten yeniden
açılmış gibi tekrar sayar ve işleri kötüleştiren adımı çöpe atar. Orijinal
dosyan asla değişmez.
Ölçtüklerimiz
- 41 modellik test setimizde (gerçek taramalar ve Thingi10K modelleri), Flap
varsayılan açıkken 41 modelin hepsi kapalı çıkıyor. Flap 13'ünde devreye
girdi ve hiçbirini kötüleştirmedi (su geçirmezlik kaybı yok, fazladan parça
yok). - Hasarlı bir taramada (thingi10k_1038441) yüzeydeki en büyük değişiklik
4,11 mm'den 0,60 mm'ye indi; çünkü delikler artık köprülenmek yerine yüzey
boyunca dolduruluyor. - Ağır hasarlı, özel bir süslü çerçeve taramasında (220 kabuk, binlerce açık
kenar) OrcaSlicer artık onarılmış dosyayı temiz görüyor: 0 açık kenar,
manifold. İnce süslemelerde gözle görülür bir fark yok. - Flap'in çekirdeği Rust ile çalışıyor: 41 modelin tamamında Flap adımı yaklaşık
7 saniye sürüyor. Rust eklentisi yoksa birebir aynı Python sürümü
kullanılıyor. - Dev taramalar artık takılmıyor. Graft'a boyut ve süre sınırı geldi; eskiden
10 dakikayı aşan altı yoğun tarama (2–6 milyon üçgen) artık 3–6 dakikada bitiyor
ve raporda dürüst bir "çok büyük, atlandı" notu yer alıyor.
Diğer yenilikler
- Kendisiyle kesişme raporlaması (
--si-mode). Dilimleyicilerin görmezden
geldiği küçük kesişmeler artık raporlanıyor ama onarımı başarısız saydırmıyor
(varsayılanreport).--si-mode repairkatı davranışı geri getirir,off
kontrolü atlar. - Pansuman (Dressing, yöntem #16), isteğe bağlı. Her zaman kapalı model
üreten ama ince ayrıntıyı yumuşatabilen bir "daldırma kaplama" onarımı.
Varsayılan kapalı; diğer tüm adımlar başarısız olursa Sutura onu önerir
(CLI ipucu, arayüzde "⚠ Dressing ile dene" butonu ve artık OrcaSlicer eklenti
panelinde de), karar senindir. - Daha az artık parça. Kâğıt inceliğinde, hacimsiz levhalar son katı
kurulmadan önce temizleniyor; kesişmeler ve başıboş parçalar azalıyor. - OrcaSlicer eklentisi yeni motoru kullanıyor ve Pansuman önerisini gösteriyor.
- Dokümanlar: README'ye (İngilizce ve Türkçe) sade bir "Sutura bir modeli
nasıl onarır" bölümü eklendi; akış artık ikiden fazla adım olduğu için "iki
aşamalı" değil "aşamalı" olarak anlatılıyor.
Varsayılanlar
| Özellik | Varsayılan | Anahtar |
|---|---|---|
| Flap yüzey delik doldurma | açık | --no-flap, SUTURA_FLAP=0 |
| Kendisiyle kesişme | raporlanır, hata sayılmaz | --si-mode repair / off |
| Graft boyut/süre sınırı | yoğunluk ön ayarına göre | Extreme = yüz sınırı yok |
| Pansuman (Dressing) | kapalı, yalnızca önerilir | --experimental-dressing |
Dosyalar
Sutura-x86_64.AppImage: LinuxSutura-v0.8.0.dmg: macOS (imzasız; ilk açılışta Sağ Tık → Aç)sutura_geom-*.whl+sutura_geom-SHA256SUMS: yükleyicilerin otomatik kullandığı derlenmiş geometri eklentisi
Tüm teknik ayrıntılar: CHANGELOG.md
v0.7.2
Sutura v0.7.2
Feature and performance release introducing the OrcaSlicer plugin v2 with an embedded dock panel for in-slicer mesh repair, alongside significantly faster rotational symmetry detection.
Added
- OrcaSlicer plugin v2 with interactive dock panel. Directly inspect and repair plate meshes within OrcaSlicer using the newly introduced script-plugin API:
- Dock panel UI: A dedicated dockable panel on Prepare/Preview tabs providing repair preset selection (Quick, Balanced, Thorough, Extreme; Balanced default), per-object manifold inspection, read-only defect breakdown (holes, non-manifold edges, self-intersections), and one-click Repair actions ("Repair selected" and "Select broken").
- Proactive notifications: Non-manifold meshes and models with errors repaired on import trigger an OrcaSlicer notification offering a direct "Repair with Sutura" action.
- World-coordinate geometry handling: Exports preserve the instance transformation matrix (proper triangle winding for mirrored parts), merge multi-part objects, and filter out parameter modifiers/blockers.
- Non-destructive workflow: Repaired meshes load back as new objects with full undo support; outputs persist under
.sutura_work/out/(retained 7 days). - Plugin installation (requires OrcaSlicer nightly / >2.4.2; stable 2.4.x has no plugin system):
Enable and launch the plugin via OrcaSlicer's Plugins dialog.
# Ensure Sutura CLI is installed (~/.local/bin/sutura via ./install.sh or ./install-macos.sh) mkdir -p ~/.config/OrcaSlicer/orca_plugins/SuturaRepair # macOS: ~/Library/Application Support/OrcaSlicer/orca_plugins/SuturaRepair cp orcaslicer-plugin/sutura_repair_linux_x86_64.py ~/.config/OrcaSlicer/orca_plugins/SuturaRepair/
Changed
- Rotational symmetry detection is 2–3.7x faster. Vectorised and multithreaded nearest-neighbour (cKDTree) queries in
detect_rotational_symmetry_freereduce corpus detection time from 59.5 s to 16.0 s while producing bit-identical results across all real-world and synthetic validation sets. - macOS GUI test environment. Test suites explicitly configure
QT_PLUGIN_PATHto resolve PySide6 Qt6 plugins in macOS conda environments when Qt5 is co-installed.
Known limitations
- OrcaSlicer version requirement: The script-plugin engine requires OrcaSlicer nightly builds or releases newer than 2.4.2; stable 2.4.x releases do not include plugin support.
- Reload mesh placement: OrcaSlicer re-centres imported meshes (or places them directly aligned with the original coordinates). Press A (Arrange) on the plate to separate the repaired object, or Cmd/Ctrl+Z to undo the reload.
Assets
Sutura-x86_64.AppImage— LinuxSutura-v0.7.2.dmg— macOS (unsigned; first launch needs right-click → Open)sutura_geom-*.whl+sutura_geom-SHA256SUMS— prebuilt geometry extension wheels used automatically by installers
Full details: CHANGELOG.md
v0.7.1
Sutura v0.7.1
Maintenance release for 0.7.0. macOS users: the 0.7.0 .dmg does not start — please use this release.
Fixed
- macOS .app/.dmg failed to start in 0.7.0. PyInstaller bundled the repository-root
sutura_enginesource-checkout bootstrap instead of the real engine package, so the CLI and the GUI exited withModuleNotFoundError. The build now packages the real engine, and CI runs the frozen CLI on every build (method list with Graft available, plus a real repair of a broken cube). Source/conda installs and the AppImage were not affected. - scipy pin restored to 1.16.x. scipy 1.18 requires Python ≥ 3.12 and broke the Python 3.11 stage-2 environment; Dependabot no longer proposes scipy ≥ 1.17.
Changed
- Graft (#13) now works in installed builds. The
sutura_geomRust extension ships with every install path:install.sh(both virtualenvs),install-macos.sh(conda env) and the self-updater install a prebuilt abi3 wheel (~0.7 MB; Linux x86_64/aarch64, macOS universal2) from this release, verified againstsutura_geom-SHA256SUMS; without a matching wheel they build fromrust/sutura-geomwhen a Rust toolchain is present, otherwise they continue without it (Graft listed unavailable, auto repair falls back to fTetWild).- The AppImage and the macOS .app/.dmg bundle the extension.
SUTURA_NO_GEOM=1opts out,SUTURA_GEOM_FROM_SOURCE=1forces a source build.
- Release assets (AppImage, .dmg, wheels) are published only for tags.
- Documentation and the About dialog now describe the product as the Sutura Triage Engine: the two-stage PyMeshLab + manifold3d core with 15 ranked repair methods.
Assets
Sutura-x86_64.AppImage— LinuxSutura-v0.7.1.dmg— macOS (unsigned; first launch needs right-click → Open)sutura_geom-*.whl+sutura_geom-SHA256SUMS— used automatically by the installers
Full details: CHANGELOG.md
v0.7.0
Note: the macOS .dmg of this release does not start (packaging bug). Use v0.7.1 or later.
Breaking / renamed
--methods 13/--methods graftnow select Method #13 Graft (shell wrap).
In v0.6.0,13andgraftwere aliases for manual repeated-element transplant;
that method is now #12transplant_plus(accessible via--methods 12/
--methods transplant_plus/--methods transplant+). Existing scripts using13
must be updated to12if manual transplant is intended.- Modular Package Structure (
sutura_engine). Core geometric passes, triage,
and diagnostics now reside undersutura_engine. Backward-compatibility shims
are maintained insutura/so existing imports continue to function without disruption.
Added
- Sutura Triage Engine Package Architecture (
sutura_engine). Modular separation
of concerns across seven dedicated subsystems:sutura_engine.triage: Auto-escalation ladder, intensity presets (Quick, Balanced,
Thorough, Extreme), and wall-clock fallback budgeting.sutura_engine.diagnosis: Object defect metrics, component inspection, and extensible
template matching (SCORE_TEMPLATES).sutura_engine.chart: High-performance SHA-256 content-addressed cache under
~/.cache/sutura/with 500 MB LRU eviction, invalidation on version bump, and
--no-cache/sutura clear-cachecontrols.sutura_engine.stitch: P-WELD reload-safe seam healing eliminating float32 vertex
collapse without altering face topologies.sutura_engine.xray: P-HONEST strict verification confirming meshes reload
strictly watertight from disk before claiming success.sutura_engine.hull: Exterior shell extraction and degenerate multi-component resolution.sutura_engine.cast: Integration with the Rustsutura_geomcore for exact predicates
and accelerated morphology.
- Extensible Plugin API (
sutura_engine.methods). ImplementedRepairMethodProtocol
andregister_methodallowing custom or experimental repair passes to be registered
dynamically with custom ranking scoring, execution context (RepairContext), and
isolated reporting (MethodResult). - Method #13 Graft (
sutura_engine.graft, legacysutura/shell_wrap.py).
Morphology shell-wrap repair tier using generalized-winding signed distance (Cast core)
and true EDT dilation/erosion to close large openings while keeping healthy triangles
verbatim. Placed on the auto-triage ladder ahead of fTetWild, with an automatic
fidelity fallback to fTetWild if healthy detail deviation is detected (fidelity_ok). - Method #14 Mirror Complete (
sutura_engine.mirror). Symmetry-plane reflection
and outer-shell fusion for single-sided symmetric scans. - Method #15 Wall Thicken (
sutura_engine.wall). Opt-in thin-wall thickening
based on signed-distance field sampling and morphological dilation. - Learning Triage (
sutura_engine.learning). Anonymous, bounded Bayesian ranking
bonus (Beta(2, 2) posterior) derived from local(template, method)history in
~/.local/share/sutura/triage_learning.json(sutura clear-learning). - Auto-escalation Fallback Time Budget. Enforced wall-clock budget
(min(max(30 s, 2 × baseline), 120 s)) bounding secondary method attempts on
failing baselines without interrupting active operations. - fTetWild Benchmark Comparison with Graft. On scan meshes requiring solidifying,
Graft produces reload-watertight output with lower runtimes while keeping
undamaged triangles byte-identical to the input.
Known limitations
- Graft (#13) extension packaging: Graft (#13) requires the optional Rust
extensionsutura_geom(build fromrust/sutura-geomwithmaturin develop --release).
The 0.7.0 installers do not bundle it yet; without it Graft is listed as
unavailable and auto repair uses fTetWild as before. Bundling is planned for
0.7.1.
Folded from the previously unreleased v0.6.1 batch
Added
-
Per-object auto escalation for multi-object 3MF. Auto escalation for
multi-object 3MF archives now operates object-by-object instead of at the file
level. Objects that are already reload-watertight after the baseline repair
pipeline are left untouched; failing objects independently escalate through
ranked recommendations (such as #8/#9 closing or #10 proxy rebuild). Each
object inobject_reportsnow carries its ownmethod_useddictionary
indicating the method number, name, and source (auto_baselinevs
auto_escalated). -
Outer-shell extraction pre-step for overlapping closed components. In
automode, when a model fits themechanicalordense_scan_heavy_si
templates and contains multiple closed components that touch or overlap (e.g.
Rubik-style assemblies or multi-part CAD imports), Sutura extracts the outer
shell prior to Stage 1. Components are dissolved via a slight dilation
(5e-4 * bbox_diagonal, ~0.05 mm for a 100 mm object) and boolean union
withmanifold3d, removing internal interfaces and degenerate
self-intersections before the main repair passes. -
Method #14 Mirror Complete (
sutura/mirror_repair.py). A symmetry-aware
alternative to Poisson closing for a single-sided scan:detect_mirror_plane
fits the dominant boundary loop's plane (planarity x dominance
confidence),mirror_closereflects the visible surface across it (winding
flipped so the shared boundary edges cancel), welds the seam and dissolves
overlapping halves into one outer shell withextract_outer_shell; low
confidence or an invalid stitch falls back to screened-Poisson reconstruction
(#8). Theclosingreport recordsmode(mirror/poisson_fallback) and
mirror_score. -
Method #15 Wall Thicken (
sutura/wall_thickness.py). Opt-in thin-wall
analysis and repair: an SDF grid (area-weighted surface samples + nearest
normal sign) yields a heatmap-ready per-vertex thickness withmin/median/
mean, andthicken_to_minoffsets thin walls by a morphological dilation
re-extracted with a dependency-free marching-tetrahedra pass. Excluded from
the ranking (needs_user_input), selected with--methods 15; CLI
--wall-min-thickness Tsets the target (default 1 % of the bbox diagonal). -
Learning triage (
history.py+methods.rank_methods). Each repair now
records the per-(template, method)outcome and elapsed time into
~/.local/share/sutura/triage_learning.json(anonymous: template and method
slugs only).rank_methodsadds a bounded Beta(2,2) Bayesian bonus
([0, 0.05], damped by speed, zero without data) for the templates the
analysis actually fired. Toggle withlearning_triage/SUTURA_LEARNING_TRIAGE
/--no-learning-triage; reset withsutura clear-learningor the GUI
Options → General → Reset learning button. No network.
Fixed
- The untagged automatic method fallback is now time-budgeted. When the
default pipeline is not strict-watertight and the auto path escalates to the
ranked methods, the extras run under a wall-clock budget of
min(max(AUTO_FALLBACK_MIN_S = 30 s, AUTO_FALLBACK_BUDGET_FACTOR = 2.0 × baseline seconds), AUTO_FALLBACK_MAX_S = 120 s). Once the budget is exhausted
no further method is started — a method already running is not interrupted —
the best candidate is kept, and the result carries
method_used.budget_reached,method_used.fallback_budget_sand the
"fallback budget reached" note (localized EN/TR in the GUI). A baseline that
already took longer than the 120 s ceiling skips the ranked fallback entirely
(method_used.fallback_skipped,baseline_s, "fallback skipped: baseline too
slow"). Explicitly tagged methods (--methods) are never budgeted. The
real-world corpus regression runs the untagged default path again, and the
budget-stop/skip behaviour is covered bytests/test_methods.py.
v0.6.0
Sutura v0.6.0 — repair method registry and a reload-honest watertight verdict
Highlights
- Repair method registry (#1–#12). Twelve stable methods in
sutura/methods.py;--list-methodsprints them,--analyzeperforms a
cheap per-object analysis with ranked recommendations, and--methods 2,3,5
tags the methods to try. The GUI gains a Method column in the file list
and a right-click menu (Analyze, Recommended methods, Use method,
External engines, Clear tags). Untagged repairs stay auto: the default
pipeline runs first, and on a non-watertight result the ranked fallback is
tried. - New standalone tiers.
- Single-side scan closing — #8
poisson_close, #9flat_back_close
(sutura/closing.py). - Proxy template repair — #10 (
sutura/proxy_repair.py). - Repeated-element repair — #11
repeat_auto, #12repeat_manual
(sutura/repeat_repair.py): segmentation-free rotational / translational /
helical / lattice detection, similarity and mirror alignment, forward+reverse
deviation detection, outer-shell extraction for assemblies, and an
out-of-process CSG bridge (sutura/csg_bridge.py) for Linux/AppImage.
Verified on thepatterned samples: 24-tooth gear (C₂₄, torn tooth
repaired, zero outside movement), PET bottle cap (C₁₂₀ knurls, localized
transplant), Rubik's cube (3D lattice, outer-shell repair). Continuous /
scaling shells (pistachio bowl, Sea Shell Vase) and an organic shell are
honestly reported as not transplantable.
- Single-side scan closing — #8
- Reload-honest watertight verdict. A mesh is only called watertight when
the saved file reloads strict-watertight (STL re-welds exactly-coincident
float32 vertices on load). P-HONEST downgrades a false claim and the
registry guard uses the same rule; the new P-WELD final pass heals the
seam by splitting the float32-coincidence vertex groups with a sub-ULP nudge
(face count unchanged). All seven real-world samples that previously reloaded
non-manifold now reload strictly watertight. - Packaging and docs.
csg_bridge.py/repeat_repair.py/
repeat_picker_render.pyship in every install/updater/AppImage/PyInstaller
list; new runtime dependenciesscipyandtrimesh. README/README.tr.md
document the methods table, the new tiers and the honest verdict; CHANGELOG
carries the full detail.
Notes
- The untagged default path runs the ranked fallback when the baseline is not
watertight; this is intentional (the default pipeline first, byte-identical
when it already succeeds) and is the main behavioural change of this release. - The macOS
.dmgis unsigned; the AppImage/GUI cannot self-update in place.
Full detail: CHANGELOG.md.
v0.5.1
Sutura v0.5.1: fixes for v0.5.0
A patch release fixing problems found in a full review of the v0.5.0 code and documentation. If you run v0.5.0, update to this version.
Highlights
- Self-update fix: the in-app updater copied an incomplete list of modules, so
triage.pyand three other modules could be missing after an update. It now uses one list shared withinstall.sh, and a new test fails if the two lists ever differ. - External engines: resolving an engine binary no longer follows symlinks, so an engine that runs inside a virtualenv starts with that virtualenv's interpreter.
- CI coverage: the triage, profile, engine, engine-integration, Engines GUI and fTetWild-manager test suites now run on every push and PR.
- Documentation: corrections in README.md, README.tr.md, docs/cli-gui-parity-notes.md and docs/ATTRIBUTION.md.
Fixed
- Self-update module list.
sutura/updater.py's_copy_python_filesand
_install_linuxnow copy every module the application imports:triage.py,
history.py,autorefine.pyandmesh_classifier_v2.pywere missing, so a
self-update could leave an installed module at its old version (or absent on
a fresh install) and silently degrade the engine layer. The lists are now a
singleAPP_MODULESconstant, andtests/test_updater.pyasserts it matches
install.sh's install list so the two can no longer drift. - CI test coverage. The triage (
tests/test_triage.py,
tests/test_triage_profiles.py), external-engine (tests/test_engines.py,
tests/test_engine_integration.py,tests/test_engines_gui.py) and
fTetWild-manager (tests/test_ftetwild_manager.py) suites now run in
.github/workflows/ci.yml; they existed but were never executed by CI. - Engine executable resolution.
sutura/engines.py's
resolve_executableno longer follows symlinks, so an engine whose command
is a virtualenv interpreter (.../venv/bin/python) runs inside that venv
instead of the base interpreter (which lost the venv's site-packages). This
only surfaced oncetests/test_engine_integration.pyran in CI. - Documentation corrections. In README.md / README.tr.md: the Turkish
preamble sentence that had been split across two sections was rejoined, the
localized Options tab isOnarım(notRepair), the original-view defect
RGB(235,60,70)was added to the Turkish text, theftetwild install|uninstallsubcommands are no longer described as read-only, and the
test-suite list now includes triage.docs/cli-gui-parity-notes.mdhas a
missing bullet line break fixed, anddocs/ATTRIBUTION.mdnow states that
the fTetWild fallback is active by default when installed rather than opt-in.
v0.5.0
Sutura v0.5.0 — Triage Engine
This release adds the Triage Engine: repair intensity presets, user profiles, external engines and an fTetWild install/remove manager. It also includes everything from the unreleased v0.4.2 batch.
Highlights
- Intensity presets: Quick, Balanced (recommended, default), Thorough and Extreme.
- Set with
--intensity, theSUTURA_INTENSITYenvironment variable, or theintensityconfig key. - Balanced repairs exactly like v0.4.x. The watertight + Hausdorff shape guard is always on.
- Set with
- User profiles: named, editable profiles built on a preset.
- Stored in
~/.config/sutura/profiles.json. - Listed with
--list-intensities; edited in Options > Repair.
- Stored in
- External engines: register repair tools you installed yourself with
~/.config/sutura/engines/*.toml.- An engine can run at a fixed slot in the pipeline, or you can define a fully custom
chain.toml. - Every engine result passes the same shape guard before it is used.
- Check your setup with
sutura engines list|check.
- An engine can run at a fixed slot in the pipeline, or you can define a fully custom
- fTetWild manager: a new Options > Engines tab and
sutura ftetwild status|install|uninstallshow the size, stream progress and can be cancelled.- About 105 MB to download and 538 MB installed on macOS arm64.
- Deep-repair ladder and dense-output fix: fTetWild boundaries that come back far denser than the input are decimated, and the result is accepted only if it stays watertight and within shape. Thorough and Extreme add an extra step at the density threshold.
- Tabbed Options window: General, Repair, Experimental, Engines, Updates and Changelog tabs, plus an explicit fTetWild optimisation option.
- Install and CI:
install.shfalls back to a checksum-verified standalone Python 3.11, which fixes Arch Linux.- New Linux and macOS end-to-end install workflows.
- New typical-user repair corpus.
- Fix: the app no longer aborts when closed while the background update check is running.
Measured on a 50-mesh typical-user corpus: 50/50 strictly watertight, with no timeouts. On a 115-mesh torture corpus: 109/115.
Added
- Triage Engine intensity presets (
--intensity). The post-Stage-1
effort is grouped into four read-only presets in a new single source of
truth,sutura/triage.py(INTENSITIES, anIntensitySpecdataclass,
PRESETS,resolve_intensity).--intensity quick|balanced|thorough|extreme(orSUTURA_INTENSITY, or theintensity
config key; CLI > env > config > balanced) selects them and the report
carriestriage_intensity(--humananIntensity:line). Stage 1 is
never affected — the repair mode and--profilekeep their behaviour.
balancedequals the historicalrepair.pyconstants (the module
constants are now derived from it) and is regression-tested byte-identical
on the real-world samples and typical-corpus meshes (--no-fallback-ftetwild
runs to remove fTetWild's run-to-run nondeterminism; the fTetWild tier
itself is covered by the faked-bridge tests).quickdisables the
deep-repair ladder and the fTetWild tier and has an empty decimation
ladder.thoroughraises the fTetWild budget to 600 s, the Hausdorff
sample count to 400,000 and adds thethresholddecimation rung
(DENSE_RATIO × max(input, DENSE_MIN_FACES));extremeremoves the
input-size cap, raises the budget to 1,800 s and the samples to 1,000,000,
and makes one extra fTetWild run withoptimize=Truewhen every
decimation rung of a dense boundary fails, before the undecimated
fallback. TheFTETWILD_MAX_FACESskip is now an explicit
ftetwild_enabledbool plus anftetwild_max_facesint-or-None instead
of the previous0/300000double meaning. Measured on thingi10k_73444
with--intensity thorough(stage 2 active): theoptimize=False
boundary returned 469,144 faces, the20,000/23,646rungs failed the
watertight check and thethresholdtarget of 80,000 succeeded (watertight,
adopted,shape_changedflagged at 5 % — the shape guard is invariant, not
a preset field). The CLI exposes--intensity;dry_runreports it; the
GUI adds a preset combo with per-preset EN/TR tooltips and a Reset to
recommended button on the Options Repair tab (restoring Balanced and the
default checkboxes), keeps the selection batch-wide and persists it to the
config. New suitestests/test_triage.pyand offscreen
tests/test_options_dialog.pycases, plustests/test_repair_mode.py
intensity cases. The named user-profile override layer is implemented on
top of this preset table (see the next entry). - Named intensity profiles (
--intensity <profile>). On top of the four
read-only presets, users can create, rename, duplicate and delete any
number of named profiles. A profile is a base preset plus a sparse
mapping of overrides of theIntensitySpecfields (only the fields the
user changed are stored); the built-in presets stay read-only. Profiles
are stored in a separate, schema-versioned
~/.config/sutura/profiles.json(its own file, not aconfig.jsonkey,
becauseconfig.jsonis rewritten whole and a corrupt profile blob must
never poison ambient configuration), written atomically via a temp file +
os.replace. A corrupt, unreadable, wrong-schema or absent file warns on
stderr and falls back to the built-in presets — it can never crash a
repair. Profile names must be non-empty, unique case-insensitively, and
must not shadow a built-in preset name;triage.name_errorenforces the
rules.--intensity(andSUTURA_INTENSITY/ theintensityconfig key)
accept a preset or a profile name; the new--list-intensitiesprints the
presets and the profiles with their effective values and exits. The report
carriestriage_profile_baseandtriage_overrideswhen a profile is
used, in addition totriage_intensity. The Hausdorff sample floor
(200,000) is enforced in the resolver as well as the GUI: a hand-edited
profile below it is clamped with a warning. The Options Repair tab's
combo lists the presets, a separator, then the user profiles, with
New (from the current selection/editor values), Duplicate,
Rename and Delete (confirming) buttons and an inline Profile
settings editor exposing every field with typed widgets/ranges (fTetWild
on/off, max faces with a No limit box, timeout, decimation ladder
includingthreshold, optimise retry, deep repair off/local/full, and the
floored Hausdorff samples); editing a built-in offers Save as new
profile, and Reset to recommended still selects Balanced without
deleting any profile. The watertight + Hausdorff shape guard is never a
field. EN/TR strings and hover tooltips cover the new controls. New suite
tests/test_triage_profiles.py(storage round-trip, corrupt file, name
rules, resolution precedence, the CLI listing/selection and the offscreen
GUI create/rename/duplicate/delete flow with a temporary HOME). - fTetWild tet optimisation is an explicit option. It stays off by
default (measured: only the boundary surface is used, and on
thingi10k_46012 the optimisation pass took 34 s instead of 6 s with the
same shape fidelity).--ftetwild-optimize,SUTURA_FTETWILD_OPTIMIZE=1
or theftetwild_optimizeconfig key turn it on; in the GUI it is the
Optimise tetrahedra (not recommended) box under the fTetWild fallback on
the Repair tab, with a note that it can make complex repairs several
times slower. - Options window (GUI). The batch-wide switches moved from the Options
drop-down into a separate, non-modal window with tabs General (anonymous
usage history), Repair (fTetWild fallback, + self-intersections),
Experimental (autorefine, indirect autorefine, join small components,
edge-tiebreak), Updates and Changelog. It opens from the Options
button or Ctrl+, / Cmd+,; the button still shows how many options differ
from their defaults, and the update indicator next to it opens the
Updates tab. Thechk_*widgets are the same objects, so the CLI
mapping is unchanged. - Update settings. The Updates tab has a manual Check for updates
button, an Automatic updates checkbox (the existingcheck_for_updates
key) and, enabled only while it is on, Check on every start (new
check_on_startupkey, default off).updater.should_check: automatic
updates off never checks; on checks on the existing 7-day interval; on plus
Check on every start checks at every start. AppImage builds keep their
download-from-the-releases-page behaviour. - Release notes in the GUI. The Changelog tab fetches the GitHub release
notes lazily in a background thread (4 s timeout, cached in the config
directory) and falls back to the cache or the bundledCHANGELOG.md
offline. No network access on headless Qt platforms (tests), and running
threads are waited for on close. - External repair engines and the fTetWild install manager (Triage Engine,
parts 2 and 3).sutura/engines.py(user-installed third-party repair
binaries configured as~/.config/sutura/engines/*.toml) and
sutura/ftetwild_manager.py(inspect/install/remove the optional fTetWild
extra in the Sutura environment only) are wired into the repair pipeline and
the interface. Engines are loaded once per run and slotted in at their
placement(before_stage1,after_stage1,after_stage2,
replace_ftetwild,final_fallback) or in an explicitchain.tomlorder;
load problems only warn (engine_warnings) and never fail a repair.
Every engine result passes the identical holes/non-manifold + Hausdorff
guard as fTetWild — adopted only when no worse on holes+non-manifold, and
an adopted far-off result is flaggedshape_changed(FTETWILD_MAX_HAUSDORFF_REL)
rather than rejected; an engine cannot bypass the guard. Each run adds a
per-engine report entry (name,placement,rc,...

