Files
animation/tools/tailor/md_pari_armsweep.py
T

123 lines
5.7 KiB
Python
Raw Normal View History

# Armhole-scoop sweep for topTest1. Diagnostic, exports nothing.
#
# python tools/md_bridge.py --file tools/tailor/md_pari_armsweep.py --timeout 880
#
# HYPOTHESIS (Jeremy's): the persistent diagonal crease across the back is surplus
# WIDTH bunching where the two panels meet. The numbers say he's right, but not at
# the bust or hem — those are matched:
# bust 570 + 510 = 1080 vs bust 1083 (matched)
# hem 380 + 320 = 700 vs waist 675 (+25 ease)
# The surplus is ABOVE the bust. The panels stay near-full width up to the armhole
# while the body narrows, giving ~968 mm of cloth around a much smaller torso at
# underarm height. And the side seam only runs y 0..185, so above that the front and
# back edges are FREE — nothing stops the surplus from overlapping and pushing a
# diagonal fold across the back, which is exactly where the crease sits.
#
# Fix under test: a concave ARMHOLE SCYE. Insert one mid-point per armhole, pulled
# inward by ARM, so the upper panel narrows without touching bust width, hem taper,
# or strap position (moving the straps would re-expose the body's baked-in bra
# straps, which is the whole reason the straps exist).
#
# Inserting points SHIFTS THE LINE INDICES, so indices are computed here rather than
# hardcoded — hardcoded 0/5/7/9 has bitten this recipe twice already.
#
# 4 values x Simulate(250) ~= 4 min. PLAIN so shape is judged, not motif.
import os
import shutil
import tempfile
AVATAR_FBX = r"C:\Users\Jeremy\tinqs\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
W_FRONT, W_BACK = 570.0, 510.0
TOP = 350.0
SCOOP_FRONT, SCOOP_BACK = 105.0, 15.0
SIDE_Y = 185.0
TAPER = 95.0
ARM_H = 70.0 # mid-point sits ARM_H above SIDE_Y, i.e. y = 255
SWEEP = [0.0, 30.0, 55.0, 80.0] # mm pulled inward per side. 0 == current shape.
SIDE_FLAGS = (True, True)
SHOULDER_FLAGS = (False, False)
ARR_X = 50
report = {"combos": {}, "hypothesis": "surplus width ABOVE the bust, free edges above SIDE_Y"}
def build(width, scoop, dx, arm):
"""Return (pattern_id, idx) where idx names the line indices we must sew."""
c = width / 2.0
pts = [(c - 210.0, TOP - 25.0), # 0 strapL_outer
(c - 120.0, TOP), # 1 strapL_inner line0 = SHOULDER_L
(c - 70.0, TOP - scoop * 0.75), # 2 neck
(c, TOP - scoop), # 3 neck
(c + 70.0, TOP - scoop * 0.75), # 4 neck
(c + 120.0, TOP), # 5 strapR_inner line5 = SHOULDER_R
(c + 210.0, TOP - 25.0)] # 6 strapR_outer
if arm:
pts.append((width - arm, SIDE_Y + ARM_H)) # 7 armhole R mid (concave scye)
pts += [(width, SIDE_Y), # sideR_top
(width - TAPER, 0.0), # hemR
(TAPER, 0.0), # hemL
(0.0, SIDE_Y)] # sideL_top
if arm:
pts.append((arm, SIDE_Y + ARM_H)) # armhole L mid
# line i runs pts[i] -> pts[i+1]; derive the seam indices from the layout
n_arm = 1 if arm else 0
side_r = 6 + n_arm + 1 # sideR_top -> hemR
hem = side_r + 1
side_l = hem + 1 # hemL -> sideL_top
idx = {"shoulder_l": 0, "shoulder_r": 5, "side_r": side_r, "side_l": side_l,
"hem": hem, "n_points": len(pts)}
pid = pattern_api.CreatePatternWithPoints([(x + dx, y, 0) for (x, y) in pts])
return pid, idx
for arm in SWEEP:
key = "arm%02d" % int(arm)
utility_api.NewProject()
op = ApiTypes.ImportExportOption()
op.scale = 10.0
op.bAddArrangementPoints = True
op.bAutoTranslate = True
import_api.ImportFBX(AVATAR_FBX, op)
pf, ixf = build(W_FRONT, SCOOP_FRONT, 0.0, arm)
pb, ixb = build(W_BACK, SCOOP_BACK, 900.0, arm)
pattern_api.AddSeamlinePairGroup(pf, ixf["shoulder_l"], pb, ixb["shoulder_l"], *SHOULDER_FLAGS)
pattern_api.AddSeamlinePairGroup(pf, ixf["shoulder_r"], pb, ixb["shoulder_r"], *SHOULDER_FLAGS)
pattern_api.AddSeamlinePairGroup(pf, ixf["side_r"], pb, ixb["side_r"], *SIDE_FLAGS)
pattern_api.AddSeamlinePairGroup(pf, ixf["side_l"], pb, ixb["side_l"], *SIDE_FLAGS)
# Verify the computed indices actually point at the edges we think: shoulders
# ~93 mm, sides ~208 mm. If these drift, the index math is wrong, not the cloth.
lens = {k: [round(pattern_api.GetLineLength(pf, ixf[k]), 1),
round(pattern_api.GetLineLength(pb, ixb[k]), 1)]
for k in ("shoulder_l", "shoulder_r", "side_r", "side_l")}
fab = fabric_api.AddFabric(ZFAB)
for p in (pf, pb):
pattern_api.SetPatternPieceFabricIndex(p, fab)
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
for a in pattern_api.GetArrangementList()}
pattern_api.SetArrangement(pf, arr["Body_Front_Center_1"])
pattern_api.SetArrangement(pb, arr["Body_Back_Center_1"])
pattern_api.SetArrangementPosition(pf, ARR_X, 55, 50)
pattern_api.SetArrangementPosition(pb, ARR_X, 55, 50)
utility_api.ResetClothArrangement()
ok = utility_api.Simulate(250)
utility_api.Refresh3DWindow()
shots = export_api.ExportTurntableImages(4)
saved = {}
for i, label in ((0, "front"), (2, "back")):
if i < len(shots) and os.path.exists(shots[i]):
dst = os.path.join(tempfile.gettempdir(),
"tinqs_armsweep_%s_%s.png" % (key, label))
shutil.copyfile(shots[i], dst)
saved[label] = dst
report["combos"][key] = {"sim": ok, "arm": arm, "idx_front": ixf,
"seam_lengths": lens, "shots": saved}
result = report