import math # =========================== # 男性體型分類 # =========================== def classify_male_body_type(body_measurements): """ 根據胸圍、腰圍、臀圍判斷男生體型: 回傳其中一個: "矩形", "三角形", "倒三角", "梯形", "橢圓形" """ C = body_measurements["chest circumference"] # 胸圍 W = body_measurements["waist circumference"] # 腰圍 H = body_measurements["hip circumference"] # 臀圍 if C <= 0 or W <= 0 or H <= 0: raise ValueError("胸圍、腰圍、臀圍必須為正數") # 1) 轉成比例(避免整體放大時結果改變) total = C + W + H pC, pW, pH = C / total, W / total, H / total v = (pC, pW, pH) # 2) 各體型的「理想比例」(pC, pW, pH) ideal_patterns = { "矩形": (0.34, 0.32, 0.34), "三角形": (0.32, 0.31, 0.37), "倒三角": (0.37, 0.31, 0.32), "梯形": (0.36, 0.31, 0.33), "橢圓形": (0.32, 0.36, 0.32), } # 3) 表格規則的門檻 def gate_rect(C, W, H): # 胸臀差 ≤ 5%,腰比胸臀小 diff_CH = abs(C - H) / max(C, H) return diff_CH <= 0.05 and W <= min(C, H) def gate_tri(C, W, H): # 三角形(下寬上窄):臀比胸大 > 10%,且腰比胸臀都小 return (H >= C * 1.10) and (W <= min(C, H)) def gate_inv(C, W, H): # 倒三角(上寬下窄):胸比臀大 > 10%,且腰比胸臀都小 return (C >= H * 1.10) and (W <= min(C, H)) def gate_trap(C, W, H): # 梯形:胸比臀大 5%~10%,腰比胸臀小 return (C > H * 1.05) and (C <= H * 1.10) and (W <= min(C, H)) def gate_oval(C, W, H): # 橢圓形:腰比胸臀都大 5% 以上 return (W >= C * 1.05) and (W >= H * 1.05) gates = { "矩形": gate_rect, "三角形": gate_tri, "倒三角": gate_inv, "梯形": gate_trap, "橢圓形": gate_oval, } def dist(a, b): return math.sqrt( (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2 ) # 4) 先找有通過門檻的 candidates = [] for name in ideal_patterns.keys(): if gates[name](C, W, H): d = dist(v, ideal_patterns[name]) candidates.append((d, name)) if candidates: candidates.sort() return candidates[0][1] # 5) 若完全沒有門檻通過,就純看誰最接近 ideal pattern best_name = None best_d = float("inf") for name, ideal_v in ideal_patterns.items(): d = dist(v, ideal_v) if d < best_d: best_d = d best_name = name return best_name # =========================== # 女性體型分類 # =========================== def classify_female_body_type(body_measurements): """ 使用【比例】而不是【公分】來判斷女性體型,並引入 ideal_patterns + 距離判斷: - 沙漏型:胸 & 臀 都明顯 > 腰,且胸臀相近 - 蘋果型:腰明顯 > 臀(且多半 ≥ 胸) - 梨型:臀明顯 > 肩寬x2 - 倒三角型:肩寬x2 明顯 > 臀 - H 型:胸/腰/臀差距都不大、肩寬x2 與 臀也接近 回傳: "蘋果型", "梨型", "沙漏型", "倒三角型", "H 型" """ C = body_measurements["chest circumference"] # 胸圍(任意長度單位) W = body_measurements["waist circumference"] # 腰圍 H = body_measurements["hip circumference"] # 臀圍 S = body_measurements["shoulder breadth"] # 肩寬(寬度,不是圍度) shoulders2 = S * 2 if min(C, W, H, shoulders2) <= 0: raise ValueError("胸/腰/臀/肩寬 必須為正數") # ========= 1) 轉成比例(不吃單位) ========= total = C + W + H pC, pW, pH = C / total, W / total, H / total v = (pC, pW, pH) # ========= 2) 各體型的 ideal pattern(比例) ========= ideal_patterns = { "沙漏型": (0.35, 0.30, 0.35), # 胸 & 臀大、腰細 "蘋果型": (0.32, 0.36, 0.32), # 腰較大 "梨型": (0.32, 0.31, 0.37), # 臀較大 "倒三角型": (0.37, 0.31, 0.32), # 胸較大 "H 型": (0.34, 0.32, 0.34), # 三者接近 } def dist(a, b): return math.sqrt( (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2 ) # ========= 3) 定義比例型 gate(門檻) ========= cw_ratio = (C - W) / W # 胸比腰大幾% hw_ratio = (H - W) / W # 臀比腰大幾% hip_shoulder_diff = (H - shoulders2) / H # 臀比肩寬x2 大幾%(<0 表肩更寬) ch_diff_ratio = abs(C - H) / max(C, H) # 胸臀接近程度 w_vs_ch_hip = (W - min(C, H)) / min(C, H) # 腰比胸/臀大多少(判斷蘋果用) # 沙漏型 gate:胸 & 臀 都比腰大,且胸臀接近 def gate_hourglass(C, W, H, shoulders2): return (cw_ratio >= 0.25 and hw_ratio >= 0.30 and ch_diff_ratio <= 0.07) # 蘋果型 gate:腰明顯 > 臀(通常也 ≥ 胸) def gate_apple(C, W, H, shoulders2): return (W >= max(C, H)) and ((W - H) / H > 0.03) # 梨型 gate:臀明顯 > 肩寬x2(原本「> 3cm」,改成約 3%) def gate_pear(C, W, H, shoulders2): return hip_shoulder_diff > 0.03 # 倒三角 gate:肩寬x2 明顯 > 臀 def gate_inv_tri(C, W, H, shoulders2): return hip_shoulder_diff < -0.03 # H 型 gate:肩寬x2 與 臀差距小,胸臀也跟腰差距不算大 def gate_h(C, W, H, shoulders2): return ( abs(hip_shoulder_diff) <= 0.03 and abs(cw_ratio) <= 0.25 and abs(hw_ratio) <= 0.25 and w_vs_ch_hip < 0.10 # 腰不會比胸/臀大太多(避免蘋果) ) gates = { "沙漏型": gate_hourglass, "蘋果型": gate_apple, "梨型": gate_pear, "倒三角型": gate_inv_tri, "H 型": gate_h, } # ========= 4) 先找「有通過門檻」的體型,裡面選距離最近 ========= candidates = [] for name in ideal_patterns.keys(): if gates[name](C, W, H, shoulders2): d = dist(v, ideal_patterns[name]) candidates.append((d, name)) if candidates: candidates.sort() return candidates[0][1] # ========= 5) 若完全沒有門檻通過,就純看 ideal pattern 距離 ========= best_name = None best_d = float("inf") for name, ideal_v in ideal_patterns.items(): d = dist(v, ideal_v) if d < best_d: best_d = d best_name = name return best_name # =========================== # 測試範例 # =========================== if __name__ == "__main__": # === 男性測試資料(用你之前那組) === male_body_measurements = { "height": 196.27, "shoulder to crotch height": 77.3, "arm left length": 55.35, "arm right length": 58.13, "inside leg height": 81.09, "shoulder breadth": 62.82, "arm length (shoulder to elbow)": 36.15, "crotch height": 83.7, "Hip circumference max height": 94.81, "arm length (spine to wrist)": 32.54, "head circumference": 60.98, "neck circumference": 33.72, "chest circumference": 150.78, "waist circumference": 154.85, "hip circumference": 158.92, "wrist right circumference": 25.12, "bicep right circumference": 39.0, "forearm right circumference": 35.64, "thigh left circumference": 72.86, "calf left circumference": 49.86, "ankle left circumference": 29.34 } male_type = classify_male_body_type(male_body_measurements) print("男性體型判斷結果:", male_type) # === 女性測試資料(先給一組假資料,你之後可以換成實際量測) === female_body_measurements = { "height": 165.0, "shoulder to crotch height": 60.0, "arm left length": 50.0, "arm right length": 50.0, "inside leg height": 75.0, "shoulder breadth": 40.0, # 肩寬 40 → 肩寬x2 = 80 "arm length (shoulder to elbow)": 30.0, "crotch height": 78.0, "Hip circumference max height": 95.0, "arm length (spine to wrist)": 30.0, "head circumference": 55.0, "neck circumference": 33.0, "chest circumference": 90.0, # 胸 90 "waist circumference": 70.0, # 腰 70 "hip circumference": 95.0, # 臀 95 "wrist right circumference": 16.0, "bicep right circumference": 28.0, "forearm right circumference": 24.0, "thigh left circumference": 55.0, "calf left circumference": 36.0, "ankle left circumference": 22.0 } female_type = classify_female_body_type(female_body_measurements) print("女性體型判斷結果:", female_type)