Skip to main content
femkeblanco
Legend
June 23, 2021
Question

Hexagonal tiles script

  • June 23, 2021
  • 2 replies
  • 1032 views

The script overlays hexagonal tiles above a selected path. It's a little slow, but I've tested it to up to a thousand tiles and it got the job done (in four minutes). Still, proceed within reason, as there is no error handling. It's based on this script from the defunct Scriptographer plugin. 

 

 

/*
 * Hexagonal Tiles by Femke Blanco
 * Beta 23/06/2021
 * Based on Hexagonal Rasterizer by xoihazard @ http://scriptographer.org
 * License: https://scriptographer.org/license/
 */
var grid;
(app.activeDocument.groupItems.add()).name = "group";
var Grid = function(cellShape, cellSize, contentScale) {
    this.cellShape = cellShape;
    this.cellSize = cellSize;
    this.contentScale = contentScale;
    this.originX;
    this.originY;
};
Grid.prototype = {
    draw: function() {
        app.activeDocument.groupItems["group"].remove();
        var group = app.activeDocument.groupItems.add();
        group.name = "group";
        var source1 = app.selection[0];
        var source2 = source1.duplicate(app.activeDocument);
        var fence = app.activeDocument.pathItems.rectangle(
            source2.top + this.cellSize, source2.left - this.cellSize,
            source2.width + this.cellSize * 2, source2.height + this.cellSize * 2,
            );
        fence.stroked = false;
        fence.filled = false;
        var hypotenuse = Math.sqrt(
            Math.pow(fence.width / 2, 2) + Math.pow(fence.height / 2, 2)
            );
        var radius = Math.ceil(hypotenuse / this.cellSize * 4 / 3);
        var bounds1 = source1.geometricBounds;
        var bounds2 = fence.geometricBounds;
        this.originX = bounds1[0] + (bounds1[2] - bounds1[0]) / 2;
        this.originY = bounds1[1] + (bounds1[3] - bounds1[1]) / 2;
        var size1 = this.cellSize / 2;
        var size2 = this.cellSize * Math.sqrt(3) / 2;
        var size3 = this.cellSize * 3 / 4;
        var counter = 1;
        for (var i = 0; i < radius; i++) {
            var cells = this.getCells(i);
            for (var j = 0; j < cells.length; j++) {
                var paths = [];
                cells[j].getXY();
                if (cells[j].x > bounds2[0] && cells[j].x < bounds2[2] && 
                    cells[j].y < bounds2[1] && cells[j].y > bounds2[3]) {
                    if (this.cellShape.text == "Hexagon") {
                        paths[j] = app.activeDocument.pathItems.polygon(
                            cells[j].x, cells[j].y, size1, 6
                            );
                        paths[j].rotate(90);
                    } else if (this.cellShape.text == "Circle") {
                        paths[j] = app.activeDocument.pathItems.ellipse(
                            cells[j].y + size2 / 2, cells[j].x - size2 / 2,
                            size2, size2
                            );
                    } else {
                        paths[j] = app.activeDocument.pathItems.rectangle(
                            cells[j].y + size3 / 2, cells[j].x - size2 / 2,
                            size2, size3
                            );
                    }
                    if (this.testForOverlap(paths[j], source2)) {
                        if (this.contentScale != 1) {
                            paths[j].resize(
                                this.contentScale * 100, this.contentScale * 100
                                );
                        }
                        paths[j].moveToBeginning(group);
                        paths[j].name = counter;
                        counter += 1;
                    } else {
                        paths[j].remove();
                    }
                }
            }
        }
        fence.remove();
        source2.remove();
        app.redraw();
        source1.selected = true;
    },
    getCells: function(radius) {
        var cells = [];
        var cell = new Cell(-radius/2, radius);
        if (radius == 0) {
            cells.push(cell);
        } else {
            for (var i = 0; i < 6; i++) {
                for (var j = 0; j < radius; j++) {
                    cells.push(cell);
                    var addend = [[1, 0], [0.5, -1], [-0.5, -1], [-1, 0], [-0.5, 1], [0.5, 1]];
                    cell = new Cell(cell.dx + addend[i][0], cell.dy + addend[i][1]);
                }
            }
        }
        return cells;
    },
    testForOverlap: function(a, b) {
        var path1 = a.duplicate();
        var path2 = b.duplicate();
        app.selection = null;
        path1.selected = true;
        path2.selected = true;
        app.executeMenuCommand("group");
        app.executeMenuCommand("Live Pathfinder Intersect");
        app.executeMenuCommand("expandStyle");
        app.executeMenuCommand("ungroup");
        var n = app.selection.length;
        while (app.selection[0]) {
            app.selection[0].remove();
        }
        return n == 1;
    }
};
var Cell = function(dx, dy) {
    this.dx = dx;
    this.dy = dy;
    this.x;
    this.y;
};
Cell.prototype = {
    getXY: function() {
        this.x = grid.originX + this.dx * grid.cellSize * Math.sqrt(3) / 2;
        this.y = grid.originY + this.dy * grid.cellSize * 3 / 4;
    }
};
var UI = function() {
    var w = new Window("dialog", "Hexagon Tiles");
    var group1 = w.add("group");
        group1.orientation = "row";
    var group2 = group1.add("group");
        group2.preferredSize.width = 81;
        group2.orientation = "column";
        group2.alignChildren = ["right","center"];
        group2.add("statictext", undefined, "Cell Shape");
        group2.add("statictext", undefined, "Cell Size");
        group2.add("statictext", undefined, "Content Scale");
    var group3 = group1.add("group");
        group3.preferredSize.width = 81;
        group3.orientation = "column";
        group3.alignChildren = ["left","center"];
    var drop1 = group3.add(
        "dropdownlist", undefined, ["Hexagon", "Circle", "Rectangle"]
        );
        drop1.selection = 0;
        var cellShape = drop1.selection;
        drop1.onChange = function () {
            cellShape = drop1.selection;
        };
    var edittext1 = group3.add("edittext", undefined, "10");
        edittext1.characters = 7;
        edittext1.active = true;
        var cellSize = Number(edittext1.text);
        edittext1.onChange = function () {
            cellSize = Number(edittext1.text);
        };
    var edittext2 = group3.add("edittext", undefined, "1");
        edittext2.characters = 7;
        var contentScale = Number(edittext2.text);
        edittext2.onChange = function () {
            contentScale = Number(edittext2.text);
        };
    var button1 = w.add("button", undefined, "Preview");
        button1.onClick = function () {
            grid = new Grid(cellShape, cellSize, contentScale);
            grid.draw();
        };
    var button2 = w.add("button", undefined, "Done");
        button2.onClick = function () {
            w.close();
        };
    w.show();
};
if (app.selection.length == 1 && app.selection[0].typename == "PathItem") {
    UI();
} else {
    alert("Select one path item.");
}

 

This topic has been closed for replies.

2 replies

Sergey Osokin
Inspiring
June 28, 2021

Redrawing app.redraw(); the interface always slows down the script. If there is no way to do without it here, I suggest using this trick. Remember the current state of the view and temporarily bring it to full screen. Then there is no interface left on the user's monitor, which is updated every time.

button1.onClick = function () {
    var userView = app.activeDocument.views[0].screenMode;
    app.activeDocument.views[0].screenMode = ScreenMode.FULLSCREEN;
    grid = new Grid(cellShape, cellSize, contentScale);
    grid.draw();
    app.activeDocument.views[0].screenMode = userView;
};

 

 

CarlosCanto
Community Expert
Community Expert
June 28, 2021

also, if you switch to Outline View, the screen redraws faster.

CarlosCanto
Community Expert
Community Expert
June 24, 2021

ah the great Scriptographer, brings back memories.

 

I was getting a somewhat inconsistent error at the line that removes the "group", I added a try/catch to fix

 

    draw: function() {
        try {
            app.activeDocument.groupItems["group"].remove();
        }
        catch (e) {}
        var group = app.activeDocument.groupItems.add();