/* * Hexagonal Rasterizer for Scriptographer.org * by xoihazard (http://xoihazard.com) * */ var params = { shape: 'Hexagon', size: 10, angle: 15, threshold: 0, cell_scale: 1.0, adaptive_size: false }; var components = { ruler1: { type: 'ruler', label: 'Grid' }, size: { type: 'number', label: 'Space', min: 1, steppers: true }, angle: { type: 'number', label: 'Angle', steppers: true }, ruler2: { type: 'ruler', label: 'Cell' }, shape: { type: 'list', label: 'Shape', options: ['Hexagon', 'Circle', 'Incircle'] }, cell_scale: { type: 'number', label: 'Rescale', min: 0, steppers: true }, threshold: { type: 'number', label: 'Threshold', range: [0, 1], steppers: true }, adaptive_size: { type: 'checkbox', label: 'Adaptive rescale' }, ruler3: { type: 'ruler' }, btn1: { type: 'button', value: 'Draw', fullSize: true, onClick: function() { grid.run(); } }, btn2: { type: 'button', value: 'Reset', fullSize: true, onClick: function() { palette.reset(); } }, credits: { type: 'text', fullSize: true, value: 'xoihazard 20140303' } }; var Grid = function() {}; Grid.prototype = { run: function() { try { this.draw(); } catch (e) { Dialog.alert(e); } }, draw: function() { var target; try { target = this.createTargetPath(); } catch (e) { throw e; } if (params.size <= 0 || params.cell_scale <= 0) { throw 'Invalid parameter.'; } var group = new Group(); var bounds = new Rectangle( target.bounds.x - params.size, target.bounds.y - params.size, target.bounds.width + params.size * 2, target.bounds.height + params.size * 2 ); var radius = Math.ceil(bounds.center.getDistance(bounds.topLeft) / params.size * 2 / 3); for (var i = 0; i < radius; i++) { var ring = this.getRing(i); for (var j = 0; j < ring.length; j++) { var hex = ring[j]; hex.setConvertion( params.size, bounds.center.x, bounds.center.y, params.angle / 180 * Math.PI ); if (bounds.contains(hex.getPoint())) { var path; var delFlag = false; var scale = params.cell_scale; switch (params.shape) { case 'Hexagon': path = new Path(hex.getHexSegments()); path.closePath(); break; case 'Circle': path = new Path.Circle(hex.getPoint(), params.size); break; case 'Incircle': path = new Path.Circle(hex.getPoint(), params.size * Math.sqrt(3) / 2); break; } if (path.intersects(target)) { if (params.threshold > 0 || params.adaptive_size) { var cellArea = path.area; var intersect = path.intersect(target); var intersectArea = intersect.area || 0; intersect.remove(); var includeRatio = Math.abs(intersectArea / cellArea); if (params.adaptive_size) { scale *= includeRatio; } if (includeRatio < params.threshold) { delFlag = true; } } } else { delFlag = true; } if (delFlag) { path.remove(); } else { if (scale !== 1) { path.scale(scale); } group.appendTop(path); } } } document.redraw(); } target.remove(); }, createTargetPath: function() { var target; var paths = []; var selectedPaths = document.getItems({type: [Path], selected: true}); if (!selectedPaths.length) { throw 'Please select a path item.'; } else { for (var i = 0; i < selectedPaths.length; i++) { paths.push(selectedPaths[i].clone()); } } target = new CompoundPath(paths); target.fillColor = null; target.strokeColor = null; return target; }, getRing: function(radius) { var results = []; var hex = new Hex(-radius, radius); if (radius === 0) { results.push(hex); } else { for (var i = 0; i < 6; i++) { for (var j = 0; j < radius; j++) { results.push(hex); hex = hex.getNeighbor(i); } } } return results; } }; var Hex = function(q, r) { this.q = 0 || q; this.r = 0 || r; this.x = 0; this.y = 0; this.size = 0; this.cx = 0; this.cy = 0; this.angle = 0; }; Hex.prototype = { setConvertion: function(size, cx, cy, angle) { this.size = size; this.cx = cx; this.cy = cy; this.angle = angle; var x = this.size * Math.sqrt(3) * (this.q + this.r / 2); var y = this.size * 3 / 2 * this.r; this.x = x * Math.cos(this.angle) - y * Math.sin(this.angle) + this.cx; this.y = y * Math.cos(this.angle) + x * Math.sin(this.angle) + this.cy; }, getPoint: function() { return new Point(this.x, this.y); }, getHexSegments: function() { var results = []; for (var i = 0; i < 6; i++) { var angle = this.angle + 2 * Math.PI / 6 * (i + 0.5); var x = this.x + this.size * Math.cos(angle); var y = this.y + this.size * Math.sin(angle); results.push(new Segment(x, y)); } return results; }, getNeighbor: function(direction) { var neighbors = [[1, 0], [1, -1], [0, -1], [-1, 0], [-1, 1], [0, 1]]; direction = ~~direction % 6; return new Hex(this.q + neighbors[direction][0], this.r + neighbors[direction][1]); } }; var grid = new Grid(); var palette = new Palette('Hexagonal Rasterizer', components, params);