Skip to content

Commit cde3a63

Browse files
committed
Everything implemented
1 parent 15aa88e commit cde3a63

7 files changed

Lines changed: 867 additions & 433 deletions

File tree

docs/report.ipynb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@
9090
"source": [
9191
"Things to implement before Friday:\n",
9292
"1. manual pixel editor in case the pixel converter isnt perfect (still in developement - prototype exists)\n",
93-
"2. sleeves (no progress)\n",
93+
"2. sleeves (DONE)\n",
9494
"3. multiple alpha patterns on one thing - to edit them you click on the sidepanel on one of the alpha patterns and edit like normal. (DONE)\n",
9595
"5. Be able to copy an alpha pattern for continuous 'stripe' or to make a repeating pattern (maybe through the multiple alpha pattern added or have like a choice to make a vertical or horizontal repeating pattern from one alpha pattern? maybe even a hexagonal grid, square grid? offset vertical stripes over some parts of the sweater? (DONE)\n",
9696
"6. make more unit tests that have good coverage (see julians comments) (no progress)\n",
97-
"7. have the whole pattern in one pdf; so be able to have separate 'projects' at once: front panel, back panel, and sleeves. so we can design alpha patterns and fit for each aspect of the sweater and then put everything in one pdf pattern with the title of the project that we chose and the rest of the instructions. (the pdf is built, but only for one panel)\n",
98-
"8. save JSON file of current session so you don't loose progress and can import the JSON file to start back on (no progress)\n",
99-
"9. README file update to include the instructions of download and use. "
97+
"7. have the whole pattern in one pdf; so be able to have separate 'projects' at once: front panel, back panel, and sleeves. so we can design alpha patterns and fit for each aspect of the sweater and then put everything in one pdf pattern with the title of the project that we chose and the rest of the instructions. (DONE)\n",
98+
"8. save JSON file of current session so you don't loose progress and can import the JSON file to start back on (DONE)\n",
99+
"9. README file update to include the instructions of download and use. (no progress)"
100100
]
101101
}
102102
],

src/diva.jpg

36.5 KB
Loading

src/knitting_pattern/app.py

Lines changed: 378 additions & 264 deletions
Large diffs are not rendered by default.

src/knitting_pattern/image_engine.py

Lines changed: 117 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,67 @@ def overlay_stamps_on_grid(sweater_grid, stamps):
130130

131131
return res.tolist()
132132

133-
# ... (Keep your generate_multipage_pdf_figs and process_uploaded_image exactly as they were below this)
134-
def generate_multipage_pdf_figs(matrix, shaping_data, title="Knitting Blueprint", rows_per_page=60):
133+
def get_panel_instructions(panel_type, shaping, co_sts="?"):
134+
"""Generates the text instruction block for the PDF based on the panel type."""
135+
if not shaping: shaping = {}
136+
137+
if panel_type == "Front Panel":
138+
first_turn = shaping.get("first_turn_stitch", "?")
139+
steps = shaping.get("total_short_row_steps", 1)
140+
sts_per_step = shaping.get("sts_per_step", "?")
141+
next_turns = max(0, steps - 1)
142+
143+
return (
144+
"FRONT PANEL SHAPING (German Short Rows):\n"
145+
f"Cast on {co_sts} stitches.\n"
146+
"Work left and right shoulder short rows simultaneously.\n\n"
147+
148+
"RIGHT SHOULDER (Row 1):\n"
149+
f"• Work {first_turn} sts, turn.\n"
150+
f"• Next {next_turns} turns: Work {sts_per_step} sts past last turn.\n\n"
151+
152+
"LEFT SHOULDER (Row 2):\n"
153+
f"• Work {first_turn} sts, turn.\n"
154+
f"• Next {next_turns} turns: Work {sts_per_step} sts past last turn.\n\n"
155+
156+
"BODY PANEL:\n"
157+
"• Work even in pattern until desired length."
158+
)
159+
160+
elif panel_type == "Back Panel":
161+
sts_per_step = shaping.get("sts_per_step", "?")
162+
first_knit = shaping.get("first_turn_stitch", "?")
163+
purl_dist = shaping.get("purl_distance", "?")
164+
165+
return (
166+
"BACK PANEL SHAPING (German Short Rows):\n"
167+
f"Row 0: Cast on {co_sts} stitches.\n\n"
168+
f"Row 1 (RS): Knit {first_knit} sts. Make a double stitch and turn.\n"
169+
f"Row 2 (WS): Purl {purl_dist} sts. Make a double stitch and turn.\n\n"
170+
"Continue working back and forth. Each time you reach a double stitch,\n"
171+
f"knit (or purl) it together as one stitch, then work {sts_per_step} more\n"
172+
"stitches past it before turning.\n\n"
173+
"Repeat this process until you reach the outer edges of the garment."
174+
)
175+
176+
elif panel_type == "Sleeve":
177+
straight = shaping.get("straight_rows", "?")
178+
dec_rate = shaping.get("dec_rate", "?")
179+
180+
return (
181+
"SLEEVE CONSTRUCTION:\n"
182+
f"Pick up {co_sts} stitches evenly around the armhole.\n"
183+
"Place a stitch marker (PM) at the center underarm to signify the\n"
184+
"Beginning of Round (BOR).\n\n"
185+
f"Knit {straight} rounds straight.\n\n"
186+
"Decrease Round: Knit to 3 sts before SM, ssk, k1, SM, k1, k2tog.\n"
187+
"(If knitting flat: Apply the same decreases 3 sts from the edges).\n\n"
188+
f"Work a decrease round every {dec_rate} rounds until desired length."
189+
)
190+
191+
return ""
192+
193+
def generate_multipage_pdf_figs(matrix, shaping_data, title="Knitting Blueprint", rows_per_page=60, settings=None):
135194
figs = []
136195

137196
# 1. INJECT THE CAST-ON EDGE
@@ -141,64 +200,70 @@ def generate_multipage_pdf_figs(matrix, shaping_data, title="Knitting Blueprint"
141200

142201
total_rows = len(matrix)
143202
total_sts = len(matrix[0])
203+
co_sts = sum(1 for st in matrix[0] if st != -1) # Count cast-on stitches
144204

205+
pattern_row = next((y for y, row in enumerate(matrix) if 1 in row), None)
206+
pattern_str = f"Row {pattern_row}" if pattern_row else "None included"
207+
208+
panel_name = title.split(" - ")[-1] if " - " in title else title
209+
project_name = title.split(" - ")[0] if " - " in title else "Knitting Project"
210+
211+
if settings is None: settings = {}
212+
gauge_sts = settings.get("gauge_sts", "?")
213+
gauge_rows = settings.get("gauge_rows", "?")
214+
size = settings.get("target_size", "?")
215+
chest = settings.get("chest_cm", "?")
216+
145217
# ==========================================
146-
# PAGE 1: THE COVER & INSTRUCTION PAGE
218+
# PAGE 1: TITLE & LEGEND (Standalone Cover)
147219
# ==========================================
148220
fig_cover, ax_cover = plt.subplots(figsize=(11, 8.5))
149221
ax_cover.axis('off')
150222
ax_cover.set_facecolor('#F9F9F9')
151223

152-
co_sts = sum(1 for st in matrix[0] if st != -1)
153-
pattern_row = next((y for y, row in enumerate(matrix) if 1 in row), None)
154-
pattern_str = f"Row {pattern_row}" if pattern_row else "None included"
224+
cover_text = (
225+
f"🧶 {project_name.upper()}\n"
226+
f"PANEL: {panel_name.upper()}\n"
227+
"════════════════════════════════════════\n\n"
228+
"PROJECT LEGEND & METRICS:\n"
229+
f"• Target Size: {size} (Chest: {chest} cm)\n"
230+
f"• Gauge: {gauge_sts} sts & {gauge_rows} rows per 10cm\n"
231+
f"• Panel Start Width: {co_sts} sts\n"
232+
f"• Panel Total Length: {total_rows} rows\n"
233+
f"• Colorwork Starts: {pattern_str}\n"
234+
)
235+
236+
ax_cover.text(0.5, 0.6, cover_text, va='center', ha='center',
237+
fontsize=16, color='#222222', linespacing=1.8, fontfamily='sans-serif')
238+
figs.append(fig_cover)
155239

156-
if shaping_data and "mountain_rows" in shaping_data:
157-
first_turn = shaping_data.get("first_turn_stitch", "?")
158-
steps = shaping_data.get("total_short_row_steps", 1)
159-
sts_per_step = shaping_data.get("sts_per_step", "?")
160-
straight_rows = total_rows - shaping_data["mountain_rows"]
161-
162-
instructions = (
163-
f"🧶 {title.upper()}\n"
164-
"════════════════════════════════════════\n\n"
165-
"OVERALL SPECS:\n"
166-
f"• Cast On: {co_sts} sts\n"
167-
f"• Total Length: {total_rows} rows\n"
168-
f"• Colorwork Starts: {pattern_str}\n\n"
169-
170-
"⛰️ SHORT ROW SHAPING\n"
171-
"Grey blocks represent empty space (no stitches knitted).\n\n"
172-
173-
"RIGHT SHOULDER (Row 1):\n"
174-
f"• Work {first_turn} sts, turn.\n"
175-
f"• Next {steps - 1} turns: Work {sts_per_step} sts past last turn.\n\n"
176-
177-
"LEFT SHOULDER (Row 2):\n"
178-
f"• Work {first_turn} sts, turn.\n"
179-
f"• Next {steps - 1} turns: Work {sts_per_step} sts past last turn.\n\n"
180-
181-
"BODY PANEL:\n"
182-
f"• Work even for {straight_rows} rows."
183-
)
184-
else:
185-
instructions = (
186-
f"🧶 {title.upper()}\n"
187-
"════════════════════════════════════════\n\n"
188-
"OVERALL SPECS:\n"
189-
f"• Cast On: {co_sts} sts\n"
190-
f"• Total Length: {total_rows} rows\n"
191-
f"• Colorwork Starts: {pattern_str}\n\n"
192-
"• Short row shaping is disabled for this panel."
193-
)
194-
195-
ax_cover.text(0.5, 0.6, instructions, va='center', ha='center',
196-
fontsize=14, color='#222222', linespacing=1.8, fontfamily='sans-serif')
240+
# ==========================================
241+
# PAGE 2: INSTRUCTIONS (Standalone Text Page)
242+
# ==========================================
243+
if not shaping_data: shaping_data = {}
244+
# Notice we now pass `co_sts` into the helper function!
245+
shaping_instructions = get_panel_instructions(panel_name, shaping_data, co_sts)
197246

198-
figs.append(fig_cover)
247+
if not shaping_instructions:
248+
shaping_instructions = "• Shaping disabled or standard straight knitting."
249+
250+
fig_inst, ax_inst = plt.subplots(figsize=(11, 8.5))
251+
ax_inst.axis('off')
252+
ax_inst.set_facecolor('#FFFFFF')
253+
254+
inst_text = (
255+
f"PATTERN INSTRUCTIONS: {panel_name.upper()}\n"
256+
"════════════════════════════════════════\n\n"
257+
f"{shaping_instructions}"
258+
)
259+
260+
# Left-aligned and near the top for easy reading
261+
ax_inst.text(0.1, 0.85, inst_text, va='top', ha='left',
262+
fontsize=13, color='#222222', linespacing=1.8, fontfamily='sans-serif')
263+
figs.append(fig_inst)
199264

200265
# ==========================================
201-
# PAGES 2+: SLICING THE CHART INTO CHUNKS
266+
# PAGES 3+: SLICING THE CHART INTO CHUNKS
202267
# ==========================================
203268
cmap = ListedColormap(['#C0C0C0', 'white', '#FF4B4B', '#FFB000'])
204269

@@ -210,67 +275,51 @@ def generate_multipage_pdf_figs(matrix, shaping_data, title="Knitting Blueprint"
210275
fig, ax = plt.subplots(figsize=(11, 8.5))
211276
ax.imshow(chunk_matrix, cmap=cmap, vmin=-1, vmax=2)
212277

213-
# 1. SOFT BASE GRID (The light background cells)
214278
ax.set_xticks(np.arange(-.5, total_sts, 1), minor=True)
215279
ax.set_yticks(np.arange(-.5, chunk_height, 1), minor=True)
216280
ax.grid(which="minor", color="#B0B0B0", linestyle='-', linewidth=0.5)
217281
ax.tick_params(which="minor", size=0)
218282
ax.set_xticks([])
219283
ax.set_yticks([])
220284

221-
# 2. SUDOKU BLOCKS (Heavy lines every 5 blocks)
222285
sudoku_col='#595959'
223-
# Outer Bounding Box
224286
ax.axvline(-0.5, color=sudoku_col, linewidth=2)
225287
ax.axvline(total_sts - 0.5, color=sudoku_col, linewidth=2)
226288
ax.axhline(-0.5, color=sudoku_col, linewidth=2)
227289
ax.axhline(chunk_height - 0.5, color=sudoku_col, linewidth=2)
228290

229-
# Heavy Vertical Lines (Boxing every 5 stitches left-to-right)
230291
for x in range(total_sts):
231292
if (x + 1) % 5 == 0 and (x + 1) < total_sts:
232293
ax.axvline(x + 0.5, color=sudoku_col, linewidth=1.5)
233294

234-
# Heavy Horizontal Lines (Absolute tracking across chunks)
235295
for local_y in range(chunk_height):
236296
abs_y = chunk_start + local_y
237297
if abs_y % 5 == 0 and abs_y != 0:
238298
ax.axhline(local_y - 0.5, color=sudoku_col, linewidth=1.5)
239299

240-
# 3. STITCH NUMBERING (Now reads 1, 2, 3... from Left to Right)
241300
for x in range(total_sts):
242301
stitch_num = x + 1
243-
# Print the number on the 1st stitch and every 5th stitch
244302
if stitch_num == 1 or stitch_num % 5 == 0:
245-
# Top Label
246303
ax.text(x, -0.8, str(stitch_num), va='bottom', ha='center', fontsize=8, color='#444444', fontweight='bold')
247-
# Bottom Label
248304
ax.text(x, chunk_height - 0.2, str(stitch_num), va='top', ha='center', fontsize=8, color='#444444', fontweight='bold')
249305

250-
# 4. ROW NUMBERING (With explicit RS/WS and moved Cast-On)
251306
for local_y in range(chunk_height):
252307
abs_y = chunk_start + local_y
253-
254308
if abs_y == 0:
255-
# Moved to the left side (-1.0)
256309
ax.text(-1.0, local_y, "CO (WS)", va='center', ha='right', fontsize=9, fontweight='bold', color='#FFB000')
257310
elif abs_y <= 4 or abs_y % 5 == 0:
258311
if abs_y % 2 != 0:
259-
# Odd Rows are RS: Label stays on the Right
260312
ax.text(total_sts + 0.5, local_y, f"Row {abs_y} (RS)", va='center', ha='left', fontsize=8, color='#333333', fontweight='bold')
261313
else:
262-
# Even Rows are WS: Label explicitly moved to the Left
263314
ax.text(-1.0, local_y, f"Row {abs_y} (WS)", va='center', ha='right', fontsize=8, color='#333333', fontweight='bold')
264315

265-
# 5. ASYMMETRICAL MOUNTAIN ARROW (If on this chunk)
266-
if shaping_data and "mountain_rows" in shaping_data:
316+
# --- NEW: Arrow Condition ---
317+
# The blue dashed arrow will ONLY render if we are strictly on the Front Panel
318+
if shaping_data and "mountain_rows" in shaping_data and "Front Panel" in panel_name:
267319
m_row = shaping_data["mountain_rows"]
268-
269320
if chunk_start <= m_row < chunk_end:
270321
local_m_row = m_row - chunk_start
271322
midpoint = total_sts // 2
272-
273-
# We use the bold sudoku lines now, so just draw the yarn jump arrow!
274323
ax.annotate('',
275324
xy=(midpoint, 1 - chunk_start), xycoords='data',
276325
xytext=(midpoint, local_m_row - 0.5), textcoords='data',

0 commit comments

Comments
 (0)