/** * SafeSimplifyMeshToLines.jsx * Converts mesh artwork into two editable linework PDFs: * 1. Mesh-derived geometry lines * 2. Contour-style interpretive lines * Separates exterior outlines and internal structure onto distinct layers. * Safe for large meshes in Illustrator. */ (function() { if (app.documents.length === 0) { alert("Please open a document first!"); return; } var doc = app.activeDocument; var saveFolder; if (doc.saved) { saveFolder = doc.path; } else { saveFolder = Folder.selectDialog("Select folder to save PDFs:"); if (!saveFolder) { alert("No folder selected. Exiting script."); return; } } // --- Utility Functions --- function getOrMakeLayer(name, parent) { parent = parent || doc; try { return parent.layers.getByName(name); } catch (e) { var l = parent.layers.add(); l.name = name; return l; } } function blackColor() { var c = new GrayColor(); c.gray = 0; return c; } function deselectAll() { app.executeMenuCommand("deselectall"); } function safeExpandAndOutline(item) { item.selected = true; try { app.executeMenuCommand('expandStyle'); } catch(e){} try { app.executeMenuCommand('expand'); } catch(e){} try { app.executeMenuCommand('outline'); } catch(e){} deselectAll(); } function isLargeArea(path) { // Only PathItems and CompoundPathItems if (!path.filled || !("area" in path)) return false; return Math.abs(path.area || 0) > 1000; } // --- MESH-DERIVED LINE VERSION --- var meshGroup = getOrMakeLayer("Mesh-Line-Version"); var meshOutlineLayer = meshGroup.layers.add(); meshOutlineLayer.name = "Exterior Outlines"; var meshInternalLayer = meshGroup.layers.add(); meshInternalLayer.name = "Internal Structure"; // Process each pageItem individually for (var i = doc.pageItems.length - 1; i >= 0; i--) { var item = doc.pageItems[i]; // Duplicate into meshGroup var copy = item.duplicate(meshGroup, ElementPlacement.PLACEATBEGINNING); // Expand and outline safely safeExpandAndOutline(copy); // Style and move to outline or internal layer if (copy.typename === "PathItem" || copy.typename === "CompoundPathItem") { copy.strokeColor = blackColor(); copy.filled = false; if (isLargeArea(copy)) { copy.move(meshOutlineLayer, ElementPlacement.PLACEATBEGINNING); copy.strokeWidth = 0.75; } else { copy.move(meshInternalLayer, ElementPlacement.PLACEATBEGINNING); copy.strokeWidth = 0.35; if ("opacity" in copy) copy.opacity = 60; } } } // Save first PDF var pdf1 = new File(saveFolder.fsName + "/Rock_Mesh_Lines.pdf"); var pdfOptions = new PDFSaveOptions(); pdfOptions.preserveEditability = true; doc.saveAs(pdf1, pdfOptions); // --- CONTOUR-STYLE INTERPRETIVE VERSION --- var contourGroup = getOrMakeLayer("Contour-Version"); var contourOutlineLayer = contourGroup.layers.add(); contourOutlineLayer.name = "Exterior Outlines"; var contourInternalLayer = contourGroup.layers.add(); contourInternalLayer.name = "Internal Structure"; // Duplicate meshGroup items individually for contour version for (var j = meshGroup.pageItems.length - 1; j >= 0; j--) { var item = meshGroup.pageItems[j]; var copy = item.duplicate(contourGroup, ElementPlacement.PLACEATBEGINNING); if ("strokeWidth" in copy && copy.strokeWidth > 0.5) { copy.move(contourOutlineLayer, ElementPlacement.PLACEATBEGINNING); copy.strokeWidth = 0.6; } else { copy.move(contourInternalLayer, ElementPlacement.PLACEATBEGINNING); copy.strokeWidth = 0.25; if ("opacity" in copy) copy.opacity = 50; } } // Save second PDF var pdf2 = new File(saveFolder.fsName + "/Rock_Contour_Lines.pdf"); doc.saveAs(pdf2, pdfOptions); alert( "Conversion complete!\nSaved as:\n" + "- Rock_Mesh_Lines.pdf\n" + "- Rock_Contour_Lines.pdf\n\n" + "Layers separated for easy editing." ); })();