Yasu777 commited on
Commit
0c7e14f
·
verified ·
1 Parent(s): 938d0b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -165
app.py CHANGED
@@ -158,10 +158,10 @@ class KnitPatternGenerator:
158
  fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 14))
159
 
160
  try:
161
- fig.suptitle('ニット型紙 - プルオーバー(実用版)',
162
  fontsize=16, fontweight='bold', fontproperties=jp_font)
163
  except:
164
- fig.suptitle('Knit Pattern - Pullover (Practical Version)', fontsize=16, fontweight='bold')
165
 
166
  # デフォルト値の設定
167
  defaults = {
@@ -194,7 +194,7 @@ class KnitPatternGenerator:
194
  return image
195
 
196
  def _draw_front_body_ultra_simple(self, ax, m):
197
- """前身頃を2枚目画像のような実用的な形に描画"""
198
  try:
199
  ax.set_title('前身頃', fontweight='bold', fontsize=14, fontproperties=jp_font)
200
  except:
@@ -209,63 +209,52 @@ class KnitPatternGenerator:
209
  ND = m["首ぐり深さ"]
210
  AD = m["袖ぐり深さ"]
211
 
212
- # 2枚目のような実用的な座標計算
213
  neck_x0 = (W - NW) / 2
214
  neck_x1 = neck_x0 + NW
215
- neck_center = W / 2
216
  shoulder_x0 = (W - SW) / 2
217
  shoulder_x1 = shoulder_x0 + SW
 
 
 
 
218
 
219
- # 袖ぐりポイント(2枚目のような自然なカーブのため)
220
- armhole_start_y = H - 5 # 肩から少し下
221
- armhole_end_y = H - AD # 袖ぐり深さ
222
-
223
- # 1. 基本の身頃形状(2枚目に近い形)
224
- basic_shape = [
225
- (0, 0), # 左下
226
- (W, 0), # 右下
227
- (W, armhole_end_y), # 右脇
228
- (shoulder_x1, armhole_start_y), # 右肩付け根
229
- (neck_x1, H), # 右首ぐり開始
230
- (neck_x0, H), # 左首ぐり開始
231
- (shoulder_x0, armhole_start_y), # 左肩付け根
232
- (0, armhole_end_y), # 左脇
233
- ]
234
 
235
- # 基本形状を描画
236
- body = patches.Polygon(basic_shape, closed=True,
237
- linewidth=2, edgecolor='black',
238
- facecolor='lightblue', alpha=0.3)
239
- ax.add_patch(body)
240
-
241
- # 2. 首ぐりのU字カーブ(実用的な深さ)
242
- neck_arc = patches.Arc(
243
- (neck_center, H - ND + 2), # 中心を少し上に
244
- width=NW, # 幅
245
- height=ND * 1.5, # 高さを調整
246
- theta1=0, theta2=180, # 上半円
247
- linewidth=2, edgecolor='black'
248
- )
249
- ax.add_patch(neck_arc)
250
-
251
- # 3. 左右の袖ぐりカーブ(2枚目のような自然なカーブ)
252
- # 左袖ぐり
253
- left_arc = patches.Arc(
254
- (shoulder_x0 + 3, H - AD/2),
255
- width=AD * 0.8, height=AD * 1.2,
256
- theta1=225, theta2=315, # より自然な角度
257
- linewidth=2, edgecolor='black'
258
- )
259
- ax.add_patch(left_arc)
260
-
261
- # 右袖ぐり
262
- right_arc = patches.Arc(
263
- (shoulder_x1 - 3, H - AD/2),
264
- width=AD * 0.8, height=AD * 1.2,
265
- theta1=225, theta2=315, # より自然な角度
266
- linewidth=2, edgecolor='black'
267
- )
268
- ax.add_patch(right_arc)
269
 
270
  # 寸法線
271
  self._add_dimension_line(ax, 0, -8, W, -8, f"身幅: {W}cm", 'below')
@@ -280,7 +269,7 @@ class KnitPatternGenerator:
280
  ax.set_ylabel('丈 (cm)')
281
 
282
  def _draw_back_body_ultra_simple(self, ax, m):
283
- """後身頃を2枚目画像のような実用的な形に描画"""
284
  try:
285
  ax.set_title('後身頃', fontweight='bold', fontsize=14, fontproperties=jp_font)
286
  except:
@@ -295,64 +284,51 @@ class KnitPatternGenerator:
295
  ND = m["首ぐり深さ"]
296
  AD = m["袖ぐり深さ"]
297
 
298
- # 後身頃の首ぐりは前身頃よりく狭
299
  back_neck_width = NW * 0.6
300
- back_neck_depth = ND * 0.4
301
 
 
302
  neck_x0 = (W - back_neck_width) / 2
303
  neck_x1 = neck_x0 + back_neck_width
304
- neck_center = W / 2
305
  shoulder_x0 = (W - SW) / 2
306
  shoulder_x1 = shoulder_x0 + SW
 
 
 
 
 
307
 
308
- # 袖ぐりポイント
309
- armhole_start_y = H - 5
310
- armhole_end_y = H - AD
311
-
312
- # 基本の身頃形状(前身頃と同じ構造)
313
- basic_shape = [
314
- (0, 0),
315
- (W, 0),
316
- (W, armhole_end_y),
317
- (shoulder_x1, armhole_start_y),
318
- (neck_x1, H),
319
- (neck_x0, H),
320
- (shoulder_x0, armhole_start_y),
321
- (0, armhole_end_y),
322
- ]
323
 
324
- body = patches.Polygon(basic_shape, closed=True,
325
- linewidth=2, edgecolor='black',
326
- facecolor='lightgreen', alpha=0.3)
327
- ax.add_patch(body)
328
-
329
- # 後首ぐりカーブ(浅い)
330
  if back_neck_depth > 1:
331
- neck_arc = patches.Arc(
332
- (neck_center, H - back_neck_depth + 1),
333
- width=back_neck_width,
334
- height=back_neck_depth * 1.2,
335
- theta1=0, theta2=180,
336
- linewidth=2, edgecolor='black'
337
- )
338
- ax.add_patch(neck_arc)
339
-
340
- # 袖ぐりカーブ(前身頃と同じ)
341
- left_arc = patches.Arc(
342
- (shoulder_x0 + 3, H - AD/2),
343
- width=AD * 0.8, height=AD * 1.2,
344
- theta1=225, theta2=315,
345
- linewidth=2, edgecolor='black'
346
- )
347
- ax.add_patch(left_arc)
348
 
349
- right_arc = patches.Arc(
350
- (shoulder_x1 - 3, H - AD/2),
351
- width=AD * 0.8, height=AD * 1.2,
352
- theta1=225, theta2=315,
353
- linewidth=2, edgecolor='black'
354
- )
355
- ax.add_patch(right_arc)
 
 
 
 
 
 
 
 
356
 
357
  ax.set_xlim(-15, W + 15)
358
  ax.set_ylim(-15, H + 15)
@@ -361,7 +337,7 @@ class KnitPatternGenerator:
361
  ax.set_ylabel('丈 (cm)')
362
 
363
  def _draw_sleeve_ultra_simple(self, ax, m):
364
- """袖を実用的で美しに描画(前回の良い部分を活用)"""
365
  try:
366
  ax.set_title('袖', fontweight='bold', fontsize=14, fontproperties=jp_font)
367
  except:
@@ -372,7 +348,7 @@ class KnitPatternGenerator:
372
  sleeve_length = m["袖丈"]
373
  sleeve_width = m["袖幅"]
374
 
375
- # 袖山の高さは袖ぐり深さの60%程度
376
  cap_height = m["袖ぐり深さ"] * 0.6
377
 
378
  # 袖口と袖山の幅
@@ -381,51 +357,38 @@ class KnitPatternGenerator:
381
 
382
  center_x = cap_width / 2
383
 
384
- # 袖山カーブの生成(前回の良い方法を改良)
385
- theta = np.linspace(0, np.pi, 20)
386
  cap_x = center_x + (cap_width/2) * np.cos(theta)
387
  cap_y = sleeve_length + cap_height * np.sin(theta)
388
 
389
- # 基本袖形状(台形)
390
- basic_shape = [
391
- (center_x - cuff_width/2, 0), # 左袖口
392
- (center_x + cuff_width/2, 0), # 右袖口
393
- (cap_width, sleeve_length), # 右袖山付け根
394
- (0, sleeve_length), # 左袖山付け根
395
- ]
396
 
397
- sleeve_body = patches.Polygon(basic_shape, closed=True,
398
- linewidth=2, edgecolor='black',
399
- facecolor='lightyellow', alpha=0.3)
400
- ax.add_patch(sleeve_body)
401
-
402
- # 袖山のなめらかなカーブ(Arcではなく曲線で)
403
- # のカーブ
404
- left_cap_arc = patches.Arc(
405
- (center_x - cap_width/4, sleeve_length + cap_height/2),
406
- width=cap_width/2, height=cap_height,
407
- theta1=60, theta2=120,
408
- linewidth=2, edgecolor='black'
409
- )
410
- ax.add_patch(left_cap_arc)
411
-
412
- # 右側のカーブ
413
- right_cap_arc = patches.Arc(
414
- (center_x + cap_width/4, sleeve_length + cap_height/2),
415
- width=cap_width/2, height=cap_height,
416
- theta1=60, theta2=120,
417
- linewidth=2, edgecolor='black'
418
- )
419
- ax.add_patch(right_cap_arc)
420
-
421
- # 頂上の部分
422
- top_arc = patches.Arc(
423
- (center_x, sleeve_length + cap_height * 0.8),
424
- width=cap_width * 0.3, height=cap_height * 0.4,
425
- theta1=45, theta2=135,
426
- linewidth=2, edgecolor='black'
427
- )
428
- ax.add_patch(top_arc)
429
 
430
  # 寸法線
431
  self._add_dimension_line(ax, center_x - cuff_width/2, -5, center_x + cuff_width/2, -5,
@@ -474,6 +437,31 @@ class KnitPatternGenerator:
474
  table[(i, 0)].set_facecolor('#f1f1f2')
475
  table[(i, 1)].set_facecolor('#ffffff')
476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  def _add_dimension_line(self, ax, x1, y1, x2, y2, text, position='above'):
478
  """寸法線を追加"""
479
  ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
@@ -482,6 +470,25 @@ class KnitPatternGenerator:
482
  mid_x = (x1 + x2) / 2
483
  mid_y = (y1 + y2) / 2
484
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  if position == 'above':
486
  mid_y += 2
487
  elif position == 'below':
@@ -545,10 +552,10 @@ def ocr_and_generate_pattern(image, manual_measurements_text, pattern_type):
545
  try:
546
  if pattern_type == "プルオーバー":
547
  pattern_image = generator.create_pullover_pattern(measurements)
548
- status_messages.append("🎯 2枚目画像準拠の実用的な型紙を生成しました")
549
  else:
550
  pattern_image = generator.create_pullover_pattern(measurements)
551
- status_messages.append("🎯 実用的な型紙を生成しました(現在はプルオーバーのみ対応)")
552
  except Exception as e:
553
  status_messages.append(f"❌ 型紙生成エラー: {str(e)}")
554
  pattern_image = None
@@ -566,9 +573,9 @@ def ocr_and_generate_pattern(image, manual_measurements_text, pattern_type):
566
  return pattern_image, measurements_display, status_text
567
 
568
  def create_interface():
569
- with gr.Blocks(title="ニット型紙メーカー(実用版)", theme=gr.themes.Soft()) as app:
570
- gr.Markdown("# 🧶 ニット型紙メーカー(実用版)")
571
- gr.Markdown("2枚目画像のような実用的で美しいベストの型紙を生成")
572
 
573
  with gr.Row():
574
  with gr.Column(scale=1):
@@ -619,26 +626,26 @@ def create_interface():
619
  )
620
 
621
  gr.Markdown("""
622
- ## 🎯 実用版の特長
623
 
624
- ### ✅ 2枚目画像に準拠し改良
625
- - **前身頃・後身頃**:2枚目のような実用的なベスト型の形状
626
- - **自然ぐり**:肩から脇下にかけての美カーブ
627
- - **適切ぐり**:前身頃は深U字、後身頃は浅い横型
628
- - **実用的な袖**:前回の良い部分を活かし自然カーブ
629
 
630
- ### ✅ 描画方式の改良
631
- 1. **基本多角形**:実用的な8形ベスの身頃
632
- 2. **位置調整されたArc**:より自然な位置でカーブ描画
633
- 3. **袖山の改良**:複数Arcで滑らか袖山を実現
634
- 4. **実測に基づく比率**:実際の型紙近い形状比率
635
 
636
  ## 📝 使用方法
637
  - **手動入力例**:「身丈:60、身幅:50、袖丈:55、袖幅:35、肩幅:40」
638
- - **結果**:2枚目画像ような実用的な型紙
639
 
640
- ## 💡 改良ポイント
641
- **前回の問題を解決** - 形状改善 + 2枚目準拠の身頃形状
642
  """)
643
 
644
  return app
 
158
  fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 14))
159
 
160
  try:
161
+ fig.suptitle('ニット型紙 - プルオーバー(滑らかなカーブ版)',
162
  fontsize=16, fontweight='bold', fontproperties=jp_font)
163
  except:
164
+ fig.suptitle('Knit Pattern - Pullover (Smooth Curve Version)', fontsize=16, fontweight='bold')
165
 
166
  # デフォルト値の設定
167
  defaults = {
 
194
  return image
195
 
196
  def _draw_front_body_ultra_simple(self, ax, m):
197
+ """前身頃をきれいに描画(滑らかなカーブ版)"""
198
  try:
199
  ax.set_title('前身頃', fontweight='bold', fontsize=14, fontproperties=jp_font)
200
  except:
 
209
  ND = m["首ぐり深さ"]
210
  AD = m["袖ぐり深さ"]
211
 
212
+ # 各種座標計算
213
  neck_x0 = (W - NW) / 2
214
  neck_x1 = neck_x0 + NW
215
+ neck_center = (neck_x0 + neck_x1) / 2
216
  shoulder_x0 = (W - SW) / 2
217
  shoulder_x1 = shoulder_x0 + SW
218
+
219
+ # パスの作成
220
+ # 1. 下辺から開始
221
+ path_points = [(0, 0)]
222
 
223
+ # 2. 右下角
224
+ path_points.append((W, 0))
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
+ # 3. 右側面(袖ぐり下まで)
227
+ path_points.append((W, H - AD))
228
+
229
+ # 4. 右袖ぐりカーブ
230
+ right_armhole = self._create_armhole_curve(shoulder_x1, H, AD, 'right')
231
+ path_points.extend(right_armhole)
232
+
233
+ # 5. 右肩から首ぐり開始点
234
+ path_points.append((neck_x1, H))
235
+
236
+ # 6. 首ぐりU字カーブ
237
+ neckline = self._create_neckline_path(neck_center, H, NW, ND)
238
+ path_points.extend(neckline)
239
+
240
+ # 7. 左肩
241
+ path_points.append((shoulder_x0, H))
242
+
243
+ # 8. 左袖ぐりカーブ
244
+ left_armhole = self._create_armhole_curve(shoulder_x0, H, AD, 'left')
245
+ path_points.extend(left_armhole)
246
+
247
+ # 9. 左側面
248
+ path_points.append((0, H - AD))
249
+
250
+ # 10. 閉じる
251
+ path_points.append((0, 0))
252
+
253
+ # パスを描画
254
+ path = patches.Polygon(path_points, closed=True,
255
+ linewidth=2, edgecolor='black',
256
+ facecolor='lightblue', alpha=0.3)
257
+ ax.add_patch(path)
 
 
258
 
259
  # 寸法線
260
  self._add_dimension_line(ax, 0, -8, W, -8, f"身幅: {W}cm", 'below')
 
269
  ax.set_ylabel('丈 (cm)')
270
 
271
  def _draw_back_body_ultra_simple(self, ax, m):
272
+ """後身頃をきれいに描画(滑らかなカーブ版)"""
273
  try:
274
  ax.set_title('後身頃', fontweight='bold', fontsize=14, fontproperties=jp_font)
275
  except:
 
284
  ND = m["首ぐり深さ"]
285
  AD = m["袖ぐり深さ"]
286
 
287
+ # 後身頃の首ぐりは浅い
288
  back_neck_width = NW * 0.6
289
+ back_neck_depth = ND * 0.3
290
 
291
+ # 各種座標の計算
292
  neck_x0 = (W - back_neck_width) / 2
293
  neck_x1 = neck_x0 + back_neck_width
294
+ neck_center = (neck_x0 + neck_x1) / 2
295
  shoulder_x0 = (W - SW) / 2
296
  shoulder_x1 = shoulder_x0 + SW
297
+
298
+ # パスの作成
299
+ path_points = [(0, 0)]
300
+ path_points.append((W, 0))
301
+ path_points.append((W, H - AD))
302
 
303
+ # 袖ぐりカーブ
304
+ right_armhole = self._create_armhole_curve(shoulder_x1, H, AD, 'right')
305
+ path_points.extend(right_armhole)
 
 
 
 
 
 
 
 
 
 
 
 
306
 
307
+ # 右肩から首ぐり
308
+ path_points.append((neck_x1, H))
309
+
310
+ # 浅い首ぐりカーブ
 
 
311
  if back_neck_depth > 1:
312
+ neckline = self._create_neckline_path(neck_center, H, back_neck_width, back_neck_depth, num_points=10)
313
+ path_points.extend(neckline)
314
+ else:
315
+ path_points.append((neck_x0, H))
 
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
+ # 左肩
318
+ path_points.append((shoulder_x0, H))
319
+
320
+ # 左袖ぐりカーブ
321
+ left_armhole = self._create_armhole_curve(shoulder_x0, H, AD, 'left')
322
+ path_points.extend(left_armhole)
323
+
324
+ path_points.append((0, H - AD))
325
+ path_points.append((0, 0))
326
+
327
+ # パスを描画
328
+ path = patches.Polygon(path_points, closed=True,
329
+ linewidth=2, edgecolor='black',
330
+ facecolor='lightgreen', alpha=0.3)
331
+ ax.add_patch(path)
332
 
333
  ax.set_xlim(-15, W + 15)
334
  ax.set_ylim(-15, H + 15)
 
337
  ax.set_ylabel('丈 (cm)')
338
 
339
  def _draw_sleeve_ultra_simple(self, ax, m):
340
+ """袖をきれいに描画(滑らかなカーブ版)"""
341
  try:
342
  ax.set_title('袖', fontweight='bold', fontsize=14, fontproperties=jp_font)
343
  except:
 
348
  sleeve_length = m["袖丈"]
349
  sleeve_width = m["袖幅"]
350
 
351
+ # 袖山の高さ
352
  cap_height = m["袖ぐり深さ"] * 0.6
353
 
354
  # 袖口と袖山の幅
 
357
 
358
  center_x = cap_width / 2
359
 
360
+ # 袖山カーブの生成
361
+ theta = np.linspace(0, np.pi, 30)
362
  cap_x = center_x + (cap_width/2) * np.cos(theta)
363
  cap_y = sleeve_length + cap_height * np.sin(theta)
364
 
365
+ # パスポイント作成
366
+ path_points = []
 
 
 
 
 
367
 
368
+ # 左袖口から開始
369
+ path_points.append((center_x - cuff_width/2, 0))
370
+
371
+ # 右袖口
372
+ path_points.append((center_x + cuff_width/2, 0))
373
+
374
+ #
375
+ path_points.append((cap_width, sleeve_length))
376
+
377
+ # 袖山カーブ(右から左へ)
378
+ cap_points = list(zip(cap_x, cap_y))
379
+ path_points.extend(cap_points)
380
+
381
+ # 左側面
382
+ path_points.append((0, sleeve_length))
383
+
384
+ # 閉じる
385
+ path_points.append((center_x - cuff_width/2, 0))
386
+
387
+ # パスを描画
388
+ sleeve = patches.Polygon(path_points, closed=True,
389
+ linewidth=2, edgecolor='black',
390
+ facecolor='lightyellow', alpha=0.3)
391
+ ax.add_patch(sleeve)
 
 
 
 
 
 
 
 
392
 
393
  # 寸法線
394
  self._add_dimension_line(ax, center_x - cuff_width/2, -5, center_x + cuff_width/2, -5,
 
437
  table[(i, 0)].set_facecolor('#f1f1f2')
438
  table[(i, 1)].set_facecolor('#ffffff')
439
 
440
+ def _create_neckline_path(self, x_center, y_top, width, depth, num_points=20):
441
+ """U字型の襟ぐりパスを生成"""
442
+ theta = np.linspace(0, np.pi, num_points)
443
+ x = x_center + (width/2) * np.cos(theta)
444
+ y = y_top - depth + depth * np.sin(theta)
445
+
446
+ # 左から右へのポイント
447
+ points = list(zip(x[::-1], y[::-1]))
448
+ return points
449
+
450
+ def _create_armhole_curve(self, x_shoulder, y_shoulder, armhole_depth, direction='left', num_points=10):
451
+ """袖ぐりカーブのポイントを生成"""
452
+ if direction == 'left':
453
+ # 左袖ぐり:右下から左上へのカーブ
454
+ theta = np.linspace(3*np.pi/2, 2*np.pi, num_points)
455
+ else:
456
+ # 右袖ぐり:左下から右上へのカーブ
457
+ theta = np.linspace(np.pi, 3*np.pi/2, num_points)
458
+
459
+ radius = armhole_depth * 0.8
460
+ x = x_shoulder + radius * np.cos(theta)
461
+ y = (y_shoulder - armhole_depth) + radius * np.sin(theta)
462
+
463
+ return list(zip(x, y))
464
+
465
  def _add_dimension_line(self, ax, x1, y1, x2, y2, text, position='above'):
466
  """寸法線を追加"""
467
  ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
 
470
  mid_x = (x1 + x2) / 2
471
  mid_y = (y1 + y2) / 2
472
 
473
+ if position == 'above':
474
+ mid_y += 2
475
+ elif position == 'below':
476
+ mid_y -= 2
477
+ elif position == 'left':
478
+ mid_x -= 2
479
+ elif position == 'right':
480
+ mid_x += 2
481
+
482
+ ax.text(mid_x, mid_y, text, ha='center', va='center',
483
+ fontsize=9, color='red', fontweight='bold',
484
+ bbox=dict(boxstyle='round,pad=0.3', facecolor='white', alpha=0.9, edgecolor='red'))
485
+ """寸法線を追加"""
486
+ ax.annotate('', xy=(x2, y2), xytext=(x1, y1),
487
+ arrowprops=dict(arrowstyle='<->', color='red', lw=1.5))
488
+
489
+ mid_x = (x1 + x2) / 2
490
+ mid_y = (y1 + y2) / 2
491
+
492
  if position == 'above':
493
  mid_y += 2
494
  elif position == 'below':
 
552
  try:
553
  if pattern_type == "プルオーバー":
554
  pattern_image = generator.create_pullover_pattern(measurements)
555
+ status_messages.append("🎯 数学に正確滑らかなカーブの型紙を生成しました")
556
  else:
557
  pattern_image = generator.create_pullover_pattern(measurements)
558
+ status_messages.append("🎯 滑らかカーブの型紙を生成しました(現在はプルオーバーのみ対応)")
559
  except Exception as e:
560
  status_messages.append(f"❌ 型紙生成エラー: {str(e)}")
561
  pattern_image = None
 
573
  return pattern_image, measurements_display, status_text
574
 
575
  def create_interface():
576
+ with gr.Blocks(title="ニット型紙メーカー(滑らかなカーブ版)", theme=gr.themes.Soft()) as app:
577
+ gr.Markdown("# 🧶 ニット型紙メーカー(滑らかなカーブ版)")
578
+ gr.Markdown("NumPyを使った数学に正確な滑らかなカーブで美しい型紙を生成")
579
 
580
  with gr.Row():
581
  with gr.Column(scale=1):
 
626
  )
627
 
628
  gr.Markdown("""
629
+ ## 🎯 滑らかなカーブ版の特長
630
 
631
+ ### ✅ NumPyを使っ数学的に正確なカーブ
632
+ - **連続したPolygonパス**:一体型の美しい輪郭線
633
+ - **滑らかU字襟ぐり**:数学関数で生成た自然なカーブ
634
+ - **自然ぐり**:半円弧カーブによる美し形状
635
+ - **完璧な袖**:三角関数で計算され滑らかな山
636
 
637
+ ### ✅ 技術的な改良
638
+ 1. **_create_neckline_path**:NumPy三関数でU字カブ生成
639
+ 2. **_create_armhole_curve**:左右袖ぐりを個別計算
640
+ 3. **連続パス描画**:切れ目のない一体型の輪郭
641
+ 4. **数学的精度**:理論的正確な曲線計算
642
 
643
  ## 📝 使用方法
644
  - **手動入力例**:「身丈:60、身幅:50、袖丈:55、袖幅:35、肩幅:40」
645
+ - **結果**:プロレベル滑らかで美しい型紙
646
 
647
+ ## 💡 技術的優位性
648
+ **数学的精度** - 実際型紙作成で使用される曲線を忠実に再現
649
  """)
650
 
651
  return app