const spread = doc.currentSpread;
const dpi = doc.dpi;
const mmToPx = dpi / 25.4;
// =================================================================
// INTERFAZ DE USUARIO
// =================================================================
const dlg = Dialog.create("Crear Ollados (Affinity)");
dlg.initialWidth = 360;
const col = dlg.addColumn();
const pnlConfig = col.addGroup("Configuración (mm)");
const diamCtrl = pnlConfig.addUnitValueEditor("Diámetro", UnitType.Millimetre, UnitType.Millimetre, 25, 1, 1000);
const margCtrl = pnlConfig.addUnitValueEditor("Margen", UnitType.Millimetre, UnitType.Millimetre, 20, 0, 1000);
const pnlMode = col.addGroup("Opciones de colocación");
const chkCornersOnly = pnlMode.addCheckBox("Colocar solo las 4 esquinas", false);
const pnlLados = col.addGroup("Lados a rellenar (incluye sus esquinas)");
const chkTop = pnlLados.addCheckBox("Lado Superior", true);
const chkBot = pnlLados.addCheckBox("Lado Inferior", true);
const chkLeft = pnlLados.addCheckBox("Lado Izquierdo", true);
const chkRight = pnlLados.addCheckBox("Lado Derecho", true);
const pnlDist = col.addGroup("Parámetros de distribución");
const distCtrl = pnlDist.addUnitValueEditor("Distancia mín. entre centros (mm)", UnitType.Millimetre, UnitType.Millimetre, 500, 10, 10000);
const result = dlg.runModal();
if (result.value !== DialogResult.Ok.value) return;
// =================================================================
// LÓGICA DE CREACIÓN
// =================================================================
const diam = diamCtrl.value * mmToPx;
const marg = margCtrl.value * mmToPx;
const minDist = distCtrl.value * mmToPx;
const radio = diam / 2;
const box = spread.getSpreadBaseBox(false);
const L = box.x, T = box.y;
const R = box.x + box.width, B = box.y + box.height;
// Posiciones teóricas de las 4 esquinas
const cTL = { x: L + marg + radio, y: T + marg + radio };
const cTR = { x: R - (marg + radio), y: T + marg + radio };
const cBL = { x: L + marg + radio, y: B - (marg + radio) };
const cBR = { x: R - (marg + radio), y: B - (marg + radio) };
// 1. Crear Grupo
const groupDef = ContainerNodeDefinition.create("Agujeros/Ollados");
groupDef.userDescription = "Agujeros/Ollados";
const groupBuilder = AddChildNodesCommandBuilder.create();
groupBuilder.setInsertionTarget(spread);
groupBuilder.setInsertionMode(InsertionMode.InsertAtEnd);
groupBuilder.addContainerNode(groupDef);
const groupCmd = groupBuilder.createCommand(false);
doc.executeCommand(groupCmd);
const groupNode = groupCmd.newNodes[0];
if (!groupNode) return;
// Configurar el modo de fusión del GRUPO a MULTIPLICAR
try {
groupNode.blendMode = BlendMode.Multiply;
} catch (e) {
try {
doc.executeCommand(DocumentCommand.createSetBlendMode(groupNode.selfSelection, BlendMode.Multiply));
} catch (err) {}
}
// 2. Estilo
const corteColor = CMYKf(0, 1, 0, 0);
const stroke = FillDescriptor.createSolid(corteColor, BlendMode.Multiply);
const none = FillDescriptor.createNone();
// Set para evitar duplicados en las esquinas
const pointsToDraw = [];
function addPoint(x, y) {
// Evitar duplicados exactos (margen de 0.1px por redondeos)
const exists = pointsToDraw.some(p => Math.abs(p.x - x) < 0.1 && Math.abs(p.y - y) < 0.1);
if (!exists) pointsToDraw.push({ x, y });
}
function drawCircle(cx, cy) {
const shape = ShapeEllipse.create();
const rect = new Rectangle(cx - radio, cy - radio, diam, diam);
const def = ShapeNodeDefinition.create(shape, rect, none);
const b = AddChildNodesCommandBuilder.create();
b.setInsertionTarget(groupNode);
b.addShapeNode(def);
const cmd = b.createCommand(false);
doc.executeCommand(cmd);
const node = cmd.newNodes[0];
if (node) {
const sel = node.selfSelection;
doc.executeCommand(DocumentCommand.createSetPenFill(sel, stroke));
doc.executeCommand(DocumentCommand.createSetBrushFill(sel, none));
node.lineWeightPts = 0.5;
try { node.blendMode = BlendMode.Multiply; } catch(e) {}
}
}
function calculateDistribution(startPos, endPos, isHorizontal) {
const totalLen = isHorizontal ? Math.abs(endPos.x - startPos.x) : Math.abs(endPos.y - startPos.y);
if (totalLen <= minDist) return;
const numIntervals = Math.floor(totalLen / minDist);
const actualDist = totalLen / numIntervals;
for (let j = 1; j < numIntervals; j++) {
if (isHorizontal) addPoint(startPos.x + (actualDist * j), startPos.y);
else addPoint(startPos.x, startPos.y + (actualDist * j));
}
}
// Lógica de selección selectiva
if (chkCornersOnly.value) {
addPoint(cTL.x, cTL.y);
addPoint(cTR.x, cTR.y);
addPoint(cBL.x, cBL.y);
addPoint(cBR.x, cBR.y);
} else {
if (chkTop.value) {
addPoint(cTL.x, cTL.y);
addPoint(cTR.x, cTR.y);
calculateDistribution(cTL, cTR, true);
}
if (chkBot.value) {
addPoint(cBL.x, cBL.y);
addPoint(cBR.x, cBR.y);
calculateDistribution(cBL, cBR, true);
}
if (chkLeft.value) {
addPoint(cTL.x, cTL.y);
addPoint(cBL.x, cBL.y);
calculateDistribution(cTL, cBL, false);
}
if (chkRight.value) {
addPoint(cTR.x, cTR.y);
addPoint(cBR.x, cBR.y);
calculateDistribution(cTR, cBR, false);
}
}
// Dibujar todos los puntos calculados
pointsToDraw.forEach(p => drawCircle(p.x, p.y));
Script Name: UTILIDAD Crear ollados
Author: kiniBTK
Description: Genera ollados vectoriales nativos en esquinas o lados seleccionados con control de diámetro, margen y distribución. Incluye modo de fusión Multiplicar automático para la capa técnica. Category: Imprenta / Utilidad Version: 1.6.0
Code:
"use strict";
/**
*/
const { Document } = require("/document");
const {
DocumentCommand,
AddChildNodesCommandBuilder,
InsertionMode
} = require("/commands");
const { ShapeNodeDefinition, ContainerNodeDefinition } = require("/nodes");
const { ShapeEllipse } = require("/shapes");
const { CMYKf } = require("/colours");
const { FillDescriptor } = require("/fills");
const { Rectangle } = require("/geometry");
const { Dialog, DialogResult } = require("/dialog");
const { UnitType } = require("/units");
const { BlendMode } = require("affinity:common");
function main() {
const doc = Document.current;
if (!doc) return;
}
module.exports.main = main;
main();