8. Repetir y decidir
Ocho rayos de un sol, doce lunares, una plancha de parches: el bordado está
lleno de repeticiones. Y de decisiones: si el nombre es largo, la letra va más
angosta; si la tela es oscura, el borde va más fino. En este capítulo
aprendes for para repetir e if para decidir.
for sobre un rango#
for i in 0..12 {
fill oro { shape: rayo.rotate(i * 30deg, centro) }
}0..12 son los enteros del 0 al 11: el último no se incluye. Doce vueltas,
con i valiendo 0, 1, 2… 11. Dentro, i es un Int y se usa como cualquier
valor: i * 30deg es un Angle, i * 9mm un Length.
El truco de .rotate(ángulo, centro) del capítulo 2 es lo que hace girar cada
copia alrededor del mismo punto, en vez de alrededor de su propio centro.
Los límites del rango son enteros (pueden ser expresiones o param, como
0..puntas en la estrella del capítulo 7):
t.hoop:4:3: error E001: a range is Int..Int (for i in 0..4)for sobre una lista#
Una lista se escribe entre corchetes: [2mm, 3mm, 4mm], ["ANA", "LUIS"].
Un for la recorre elemento por elemento:
const tamanos = [2mm, 3mm, 4mm, 5mm, 4mm, 3mm]
layer lunares {
for r in tamanos {
fill rojo { shape: circle(center: (65mm, 15mm), r: r) }
}
}Y con dos nombres, for x, i in …, te da también el índice (desde 0):
for r, i in tamanos {
fill rojo { shape: circle(center: (65mm + i * 9mm, 15mm), r: r) }
}len(lista) es la cantidad de elementos, y len(texto) la cantidad de
caracteres (una "Á" cuenta como uno):
// no-check Plantilla sintáctica con elipsis, no un programa ejecutable.
for i in 0..len(tamanos) { … }Algunas reglas:
Un
forva en una capa (y puede contener primitivas,inside,place,ify otrosfor) o en unhoop(conplace, capítulo 9). No va dentro de unseq.Hasta 1000 vueltas:
Salida del compiladort.hoop:4:3: error E002: 2000 iterations: a loop goes up to 1000La variable no puede tapar otro nombre:
Salida del compiladort.hoop:4:3: error E007: the loop variable `rojo` hides another name: choose anotherUn error dentro de un
forse informa una vez, no una por vuelta. Aquí sólo la tercera vuelta se sale del lienzo, y verás un solo error:Salida del compiladorvuelta.hoop:5:5: error E006: fill overflows the canvas by 9.0 mm on the right
grid: copias en filas y columnas#
Para ubicar copias en una grilla, grid calcula el punto de la celda i, de
izquierda a derecha y de arriba abajo:
grid(i, cols: 4, step: (12mm, 12mm), start: (65mm, 35mm))i: el número de celda (unInt, normalmente la variable delfor).cols: cuántas columnas tiene cada fila.step: la distancia entre celdas,(horizontal, vertical).start: el punto de la celda 0 (por defecto,(0mm, 0mm)).
Con cols: 4, la celda 5 es la segunda de la segunda fila:
(65mm + 1 × 12mm, 35mm + 1 × 12mm).
if: decidir#
if i mod 2 == 0 {
fill rojo { shape: circle(center: (65mm + i * 9mm, 15mm), r: r) }
} else {
fill azul { shape: circle(center: (65mm + i * 9mm, 15mm), r: r) }
}if condición { … } else if otra { … } else { … }: el else es opcional.
Va donde va un for: en capas y en un hoop.
La condición es un Bool. Se arma con:
- comparaciones
==,!=,<,<=,>,>=entre valores del mismo tipo (<y compañía sólo entre números:Int,Length,Angle,Ratio); and,orynotentreBool;trueyfalse.
t.hoop:4:10: error E001: cannot compare Length with Anglet.hoop:2:14: error E001: a condition is a Bool (a comparison like len(name) > 8), not Intmod: uno sí, uno no#
a mod b es el resto de dividir a por b, entre enteros. Es la manera de
decir "cada dos", "cada tres": i mod 2 == 0 es verdadero en las vueltas
pares, i mod 5 == 0 en una de cada cinco.
if como valor#
Un if también puede dar un valor, dentro de una propiedad. Entonces
lleva else, y las dos ramas dan el mismo tipo:
size: if i mod 5 == 0 { (9mm, 9mm) } else { (6mm, 6mm) }// error E001
design "Tipos" { canvas: rect(size: (20mm,20mm)) }
thread negro = #000000
layer a { fill negro { shape: rect(size: if true { 3mm } else { 2 }) } }t.hoop:3:42: error E001: both branches of an if give the same type, not Length and IntLas dos ramas se verifican#
El compilador revisa las dos ramas, aunque sólo borde la elegida. Un error en la rama que hoy no se toma se informa igual:
rama.hoop:5:5: error E003: undeclared thread `b`; did you mean `a`?Es a propósito: el día que un param cambie y se tome la otra rama, no quieres
descubrir el error en la máquina.
Un diseño con patrones#
// repetir.hoop: un sol de rayos, una fila de lunares y una grilla.
design "Patrones" {
canvas: rect(size: (120mm, 80mm))
}
thread oro = #d8a21b "Oro"
thread rojo = #cc3f24 "Rojo"
thread azul = #1f3a8a "Azul"
const centro = (30mm, 30mm)
shape rayo = polygon((28mm, 18mm), (30mm, 6mm), (32mm, 18mm))
const tamanos = [2mm, 3mm, 4mm, 5mm, 4mm, 3mm]
layer sol {
fill oro { shape: circle(center: centro, r: 10mm) }
// Doce rayos: el mismo triángulo, girado alrededor del centro.
for i in 0..12 {
fill oro { shape: rayo.rotate(i * 30deg, centro) }
}
}
layer lunares {
// Uno rojo, uno azul: el resto de dividir por 2 decide.
for r, i in tamanos {
if i mod 2 == 0 {
fill rojo { shape: circle(center: (65mm + i * 9mm, 15mm), r: r) }
} else {
fill azul { shape: circle(center: (65mm + i * 9mm, 15mm), r: r) }
}
}
}
layer grilla {
// Doce cuadritos en 4 columnas; los de la diagonal, más grandes.
for i in 0..12 {
fill azul {
shape: rect(at: grid(i, cols: 4, step: (12mm, 12mm), start: (65mm, 35mm)),
size: if i mod 5 == 0 { (9mm, 9mm) } else { (6mm, 6mm) })
}
}
}patrones.hoop: 107.0 × 62.0 mm, 4417 stitches, 3 threads, 29 trims, 28 ms29 cortes: cada lunar y cada cuadrito es una isla, y la máquina corta entre
islas. En un diseño real, piensa si las islas pueden unirse en una forma
(+), o si un corrido escondido bajo otra capa puede llevar el hilo de una a
otra. Menos islas, menos cortes.
param + if: componentes que se adaptan#
Lo más útil de if aparece con los param del capítulo 7. Esta etiqueta
elige la fuente según el largo del nombre, y el fondo y el borde según un
Bool:
// etiqueta.hoop: el nombre decide su tamaño, su forma y su color.
param nombre = "MARÍA JOSÉ"
param oscuro = false
thread blanco = #f0f0f0 "Blanco"
thread azul = #1f3a8a "Azul"
thread negro = #1c1616 "Negro"
design "Etiqueta" { canvas: rect(size: (70mm, 30mm), radius: 5mm) }
shape caja = rect(at: (6mm, 5mm), size: (58mm, 20mm))
layer fondo {
if oscuro {
fill azul { shape: canvas }
} else {
fill blanco { shape: canvas }
}
}
layer texto {
if len(nombre) > 8 and nombre != "" {
text negro { value: nombre, font: Bebas, box: caja } // largo: angosta
} else if len(nombre) > 4 {
text negro { value: nombre, font: ArialBold, box: caja }
} else {
text negro { value: nombre, font: ArialBold, height: 12mm, at: (35mm, 21mm), align: center }
}
}
layer borde {
satin negro { border: canvas, width: if oscuro { 2mm } else { 3mm } }
}Y quien la coloca decide:
design "E" { canvas: rect(size: (160mm, 40mm)) }
layer a {
place "etiqueta.hoop"(nombre: "ANA", oscuro: true) at (40mm, 20mm)
place "etiqueta.hoop"(nombre: "VALENTINA") at (120mm, 20mm)
}etiquetas.hoop: ok — 3 threads, 1 layers, 2 objects(Este archivo no declara hilos: los 3 threads del resumen son los colores
que se cosen, que vienen con las etiquetas, contados como los cuenta hoop build.)
Resumen#
for i in a..brecorre enteros deaab - 1;for x in [ … ]una lista;for x, i in …da también el índice.grid(i, cols:, step:, start:)ubica la celdaide una grilla.if … { } else if … { } else { }decide; como valor, llevaelsey ramas del mismo tipo.- Comparaciones entre valores del mismo tipo;
and,or,not;modes el resto entre enteros;lencuenta caracteres o elementos. - Las dos ramas de un
ifse verifican; un error en unforse informa una vez.
Referencia: control · expresiones · tipos