# Arrangement-x sweep for bottomTest1 (strand skirt). Diagnostic, exports nothing. # # python tools/md_bridge.py --file tools/tailor/md_piupiu_arrsweep.py --timeout 880 # # WHY: the skirt's waistband folds on ONE SIDE only (turntable side B shows a flap # jutting out with a grey reverse-face wedge and a strand group folded over itself; # side A is clean). An asymmetric defect needs an asymmetric input, and the only one # is SetArrangementPosition x: front=50 / back=0, inherited from md_piupiu.py. # # But setting BOTH to 50 — which is exactly what fixed the same one-sided fold on the # TOP — makes this skirt fall to the floor (band top measured 0.117 m). The top # arranges on Body_*_Center_1; this arranges on Leg_Skirt_Front/Back, and those points # evidently do not share a convention. So 50/0 may be load-bearing here rather than a # copy-paste artefact. # # CONTROL: combo (50, 0) must reproduce the shipped drape (band top ~1.09 m). If the # control fails, the harness is broken and every cell is void — that is exactly how # md_pari_armsweep.py wasted a run. # # Pass/fail is read from GEOMETRY, not images: a garment on the floor measures # band_top < 0.3 m, so the sweep self-reports which cells even stayed on the body. 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" M_TEETH = 16 W_TOP, W_HEM = 375.0, 700.0 BAND_H, STRAND_H = 60.0, 530.0 GAP_TOP, GAP_HEM = 6.0, 11.0 PARTICLE_MM, COLLISION_MM = 20.0, 10.0 ARR_Y = 92 COMBOS = [(50, 0), (50, 50), (0, 0), (0, 50)] # (50,0) is the CONTROL BAND_TOP = STRAND_H + BAND_H BAND_BOT = STRAND_H INSET = (W_HEM - W_TOP) / 2.0 pitch_top = W_TOP / M_TEETH pitch_hem = W_HEM / M_TEETH report = {"combos": {}, "control": "50_0", "control_expect_band_top_m": 1.09} def outline(dx): pts = [(INSET, BAND_TOP), (INSET + W_TOP, BAND_TOP), (INSET + W_TOP, BAND_BOT)] for j in range(M_TEETH - 1, -1, -1): ta = INSET + j * pitch_top + GAP_TOP / 2.0 tb = INSET + (j + 1) * pitch_top - GAP_TOP / 2.0 ha = j * pitch_hem + GAP_HEM / 2.0 hb = (j + 1) * pitch_hem - GAP_HEM / 2.0 if j < M_TEETH - 1: pts.append((tb, BAND_BOT)) pts += [(hb, 0.0), (ha, 0.0), (ta, BAND_BOT)] return [(x + dx, y, 0) for (x, y) in pts] for xf, xb in COMBOS: key = "%d_%d" % (xf, xb) utility_api.NewProject() op = ApiTypes.ImportExportOption() op.scale = 10.0 op.bAddArrangementPoints = True op.bAutoTranslate = True import_api.ImportFBX(AVATAR_FBX, op) pts_f = outline(0.0) sf = pattern_api.CreatePatternWithPoints(pts_f) sb = pattern_api.CreatePatternWithPoints(outline(W_HEM + 400.0)) L_RIGHT, L_LEFT = 1, len(pts_f) - 1 # crossed pairing: for a two-panel tube with only side seams this IS the reversal pattern_api.AddSeamlinePairGroup(sf, L_RIGHT, sb, L_LEFT, False, False) pattern_api.AddSeamlinePairGroup(sf, L_LEFT, sb, L_RIGHT, False, False) fab = fabric_api.AddFabric(ZFAB) # PLAIN: judge shape, not motif for p in (sf, sb): pattern_api.SetPatternPieceFabricIndex(p, fab) pattern_api.SetParticleDistanceOfPattern(p, PARTICLE_MM) pattern_api.SetAddlThicknessCollision(p, COLLISION_MM) arr = {a["ArrangementName"]: int(a["ArrangementIndex"]) for a in pattern_api.GetArrangementList()} pattern_api.SetArrangement(sf, arr["Leg_Skirt_Front"]) pattern_api.SetArrangement(sb, arr["Leg_Skirt_Back"]) pattern_api.SetArrangementPosition(sf, xf, ARR_Y, 50) pattern_api.SetArrangementPosition(sb, xb, ARR_Y, 50) pattern_api.SetPatternStrengthen(sf, True) pattern_api.SetPatternStrengthen(sb, True) utility_api.ResetClothArrangement() ok1 = utility_api.Simulate(250) pattern_api.SetPatternStrengthen(sf, False) pattern_api.SetPatternStrengthen(sb, False) ok2 = utility_api.Simulate(50) utility_api.Refresh3DWindow() # geometry verdict: on the floor measures band_top < 0.3 m mop = ApiTypes.ImportExportOption() mop.bExportGarment = True mop.bExportAvatar = False probe = os.path.join(tempfile.gettempdir(), "tinqs_arrsweep_%s.obj" % key) export_api.ExportOBJ(probe, mop) ys = [] with open(probe) as fh: for line in fh: if line.startswith("v "): ys.append(float(line.split()[2]) * 0.001) # OBJ is MM ys.sort() on_body = bool(ys) and ys[-1] > 0.30 shots = export_api.ExportTurntableImages(4) saved = {} for i, label in ((0, "front"), (1, "sideA"), (3, "sideB")): if i < len(shots) and os.path.exists(shots[i]): dst = os.path.join(tempfile.gettempdir(), "tinqs_arrsweep_%s_%s.png" % (key, label)) shutil.copyfile(shots[i], dst) saved[label] = dst report["combos"][key] = { "x": [xf, xb], "sim": [ok1, ok2], "on_body": on_body, "band_top_m": round(ys[-1], 3) if ys else None, "hem_m": round(ys[0], 3) if ys else None, "shots": saved} result = report