Contenido de las capas y control
Una capa (layer, ver Declaraciones) contiene
elementos de capa: primitivas de bordado y construcciones que las
ordenan (seq), las contienen (inside), las repiten (for), las eligen
(if) o traen otro diseño (place). Todo se resuelve al compilar: un for
se despliega en copias y un if se reduce a la rama elegida. Las
primitivas (fill, satin, run, triple, text) se describen en
Primitivas y Texto.
Gramática#
item_de_capa = primitiva
| "seq" "{" { item_de_capa } "}"
| "inside" expr "{" { item_de_capa } "}"
| "for" identificador [ "," identificador ] "in" expr [ ".." expr ]
"{" { item_de_capa } "}"
| si
| place ;
si = "if" expr "{" { item_de_capa } "}"
[ "else" ( si | "{" { item_de_capa } "}" ) ] ;
place = "place" texto [ "(" args ")" ] "at" expr
{ identificador ":" expr } ;
primitiva = ( "fill" | "satin" | "run" | "triple" | "text" )
nombre_de_hilo props ;Las palabras seq, inside, for, if y place se reconocen por
contexto: seq seguido de {; inside seguido de algo distinto de {;
for seguido de un identificador; place seguido de un texto. En cualquier
otro caso la palabra se lee como el inicio de una primitiva, lo que da
E000: inside is not a primitive (fill, satin, run, triple or text).
Orden de bordado#
- Las capas se bordan en el orden escrito.
- Dentro de una capa, el compilador elige el orden de los objetos (menos cortes y cambios de hilo).
- Un
seqfija el orden de su contenido.
seq#
seq = "seq" "{" { item_de_capa } "}" ; (* sin seq ni place *)Los objetos de un seq se bordan seguidos y en el orden escrito, sin
otro objeto entre medio, aunque cueste un cambio de hilo. El bloque
completo puede ir antes o después de los demás objetos de la capa.
- Un
seqcontiene primitivas y tambiénfor,ifeinside: se expanden en orden y todo lo que producen forma parte del mismo bloque (las primitivas de uninsidequedan además en su contenedor). Otroseqo unplacedentro de unseqesE000(`seq` is not allowed inside `seq` (…),`place` is not allowed inside `seq` (a placed design keeps its own order)). Unseqtambién puede ir dentro de unfor, unifo uninside. - Cada
seqescrito, y cada vuelta de unforque contiene unseq, forma un bloque independiente.
shape parche = rect(at: (20mm, 20mm), size: (60mm, 40mm), radius: 4mm)
layer aplique {
seq {
run negro { path: parche }
triple negro { path: parche, passes: 3 }
satin negro { border: parche, width: 3mm }
}
}inside#
inside = "inside" expr "{" { item_de_capa } "}" ;Declara que lo de adentro debe quedar dentro de una forma. La expresión
debe ser una forma (o un camino cerrado); si no,
E001: expected a Shape, not Length.
- Si la huella cosida de un objeto de adentro sale de la forma, el
compilador da la advertencia
W009, con cuánto y por dónde (fill overflows theinsideshape at 4:11 by 2.8 mm at the bottom). No es un error: un detalle puede salir de la forma a propósito. - Los
insidese anidan; cada objeto se compara con el más cercano que lo contiene. - Pueden contener cualquier elemento de capa (
seq,for,if,place, otrosinside). Unplacedentro de uninsidetambién se revisa contra esa forma. - El lienzo (
canvas) se verifica aparte y es error (E006);insidees para las formas del diseño.
shape escudo = rect(at: (10mm, 10mm), size: (80mm, 80mm), radius: 6mm)
layer frente {
fill blanco { shape: escudo }
inside escudo.inset(2mm) {
fill negro { shape: circle(center: escudo.center, r: 20mm) }
}
}for#
for = "for" identificador [ "," identificador ] "in" expr [ ".." expr ]
"{" { item_de_capa } "}" ;Repite su cuerpo, una vez por valor:
for x in a..brecorre los enteros desdeahastabsin incluirb. Ambos extremos deben serInt(E001: a range is Int..Int (for i in 0..4)). Sib ≤ a, el cuerpo no se ejecuta.for x in listarecorre los elementos de unaList, en orden. Cualquier otro valor esE001: for goes over a range (0..4) or a List, not Int.for x, i in …además da el índice de la vuelta eni(Int, desde 0). Vale tanto para rangos como para listas.
Reglas:
- Un
forda a lo más 1000 vueltas; más esE002: 1001 iterations: a loop goes up to 1000y no se despliega. - La variable y el índice no pueden tapar un nombre existente (constante,
forma, parámetro, hilo, otra variable de un
forexterior):E007: the loop variableihides another name: choose another. - Las variables existen solo dentro del cuerpo; al terminar el bucle dejan de existir.
- El cuerpo admite cualquier elemento de capa, incluidos otros
for. - Un mismo diagnóstico en la misma posición se informa una sola vez, aunque ocurra en varias vueltas.
shape punta = polygon((50mm, 10mm), (54mm, 40mm), (46mm, 40mm))
layer sol {
for i in 0..8 {
fill negro { shape: punta.rotate(i * 45deg, (50mm, 50mm)) }
}
for c, i in [(20mm, 80mm), (50mm, 80mm), (80mm, 80mm)] {
fill blanco { shape: circle(center: c, r: 3mm + i * 1mm) }
}
}Con grid (ver Expresiones § grid) un for ubica
copias en filas y columnas:
layer puntos {
for i in 0..6 {
fill negro { shape: circle(center: grid(i, cols: 3, step: (30mm, 30mm), start: (20mm, 30mm)), r: 4mm) }
}
}if#
si = "if" expr "{" { item_de_capa } "}"
[ "else" ( si | "{" { item_de_capa } "}" ) ] ;Elige qué bordar. El else es opcional y else if encadena.
- La condición debe ser
Bool:E001: a condition is a Bool (a comparison like len(name) > 8), not Int. - Se verifican las dos ramas (los errores de la rama que no se toma también se informan), pero solo se borda la elegida.
- Si la condición no se puede evaluar (tiene un error), no se borda ninguna rama.
Para elegir un valor en vez de elementos de capa, use la expresión
if c { a } else { b } (ver Expresiones § Expresión if).
param nombre = "MARÍA JOSÉ"
layer texto {
if len(nombre) > 8 {
text blanco { value: nombre, box: canvas.inset(5mm) }
} else if len(nombre) > 4 {
text blanco { value: nombre, height: 12mm, at: canvas.center, align: center }
} else {
text blanco { value: nombre, height: 16mm, at: canvas.center, align: center }
}
for i in 0..6 {
if i mod 2 == 1 {
fill negro { shape: circle(center: (10mm + i * 14mm, 90mm), r: if i > 3 { 4mm } else { 3mm }) }
}
}
}place#
place = "place" texto [ "(" args ")" ] "at" expr { identificador ":" expr } ;Trae otro diseño (otro archivo .hoop) como componente, en el punto at.
La ruta es relativa al archivo que contiene el place.
| Parte | Tipo | Por defecto | Significado |
|---|---|---|---|
( … ) | argumentos con nombre | — | valores para los param del diseño colocado |
at | Point | obligatorio | dónde va el ancla |
anchor | Name | center | qué punto del lienzo del componente va en at: center, top_left, top_center, top_right, center_left, center_right, bottom_left, bottom_center, bottom_right |
rotate | Angle | 0deg | giro del componente |
scale | Ratio (> 0) | 100% | escala del componente |
Semántica:
- El componente se compila con la tela (
fabric) de quien lo coloca; su lienzo da el ancla. Sus hilos y susseqvienen con él, y el compilador optimiza el orden de todo junto. - Lo cosido del componente se revisa contra el lienzo y contra los
insidedel archivo que lo coloca. - Los errores del componente se informan en la posición del
place, con la posición original dentro del otro archivo.
Errores:
atque no es un punto:E001: at takes a Point (x, y), not Length.- Argumento sin nombre:
E001: design arguments are named: place "x.hoop"(nombre: "ANA"). - Argumento para un
paramque no existe:E007:parche.hoophas no paramnombr; did you meannombre?. - Argumento de otro tipo que el
param:E001: in `parche.hoop` 1:1: error: `nombre` is String but it was given Int. - Propiedad desconocida:
E007: place has nofoo(anchor, rotate, scale);anchorfuera de la lista esE002;rotateoscalede otro tipo,E001;scaleen cero o negativo,E002:scalemust be greater than 0%. - Un modificador o argumento repetido:
E007: duplicatescale``. - Archivo que no se puede leer:
E007: cannot readnope.hoop: …. - Un diseño que se coloca a sí mismo, directa o indirectamente, es un ciclo:
E007: place cycle: a.hoop → a.hoop, en elplacede más afuera.
layer insignias {
place "parche.hoop"(nombre: "LUIS") at (50mm, 20mm) anchor: top_center scale: 90%
for nombre, i in ["ANA", "SOFÍA"] {
place "parche.hoop"(nombre: nombre, alto: 5mm) at grid(i, cols: 1, step: (0mm, 25mm), start: (50mm, 60mm)) rotate: 5deg
}
}En el ejemplo, parche.hoop es el archivo de la sección
param.
En un hoop#
Un hoop (ver Bastidor) admite place, for e if con las
mismas reglas, pero no primitivas, seq ni inside: dentro de un if o
for del hoop son
E007: a hoop only places designs (place, for); stitches go in a design, y
directamente en el hoop,
E000: a hoop only places designs (move fill into a design file).