scripts/Triangulator/Triangulator.jsx

1326 lines
36 KiB
JavaScript

//(c) www.illustratorscripts.com
(function () {
//hue variation of color of triangles
var HUE_VAR = 20;
//saturation variation of triangles
var SAT_VAR = 10;
//lightness variation of triangles
var LIGHT_VAR = 10;
//additional points to add to shape as vertices
var NUM_POINTS = 60
//setting this to [R,G,B], 0..255, ie: COL=[12,20,255]
//will override selection color being picked
var COL;
if (ScriptUI.environment.keyboardState.altKey)
NUM_POINTS = parseInt(prompt("enter point density. recommended range is 100..10000", 100))
var doc;
function main() {
if (app.documents.length == 0 || app.selection.length != 1 || !(app.selection[0].constructor.name == "PathItem" || app.selection[0].constructor.name == "CompoundPathItem")) {
alert('''
Triangulator.jsx.
Select single path or compund path. Text should be
converted to outlines first. Press [ALT] when starting script for additional options.
Check for more at illustratorscripts.com
''');
return;
}
clearConsole();
doc = app.activeDocument;
var selectedItem = doc.selection[0]
var holes = [];
var outerPath = null;
//converts compounds to holes/outer paths
if (selectedItem.constructor.name == "CompoundPathItem") {
for (p = 0; p < selectedItem.pathItems.length; p++) {
//ignore small holes
if (Math.abs(selectedItem.pathItems[p].area) < 30)
continue;
holes.push(flattenPath(selectedItem.pathItems[p]));
}
if (holes.length == 1 && outerPath == null) {
outerPath = holes[0];
holes = [];
} else {
var minx = holes[0][0][0];
var outer = 0;
for (p = 0; p < holes.length; p++) {
for (q = 0; q < holes[p].length; q++) {
if (holes[p][q][0] < minx) {
minx = holes[p][q][0];
outer = p;
}
}
}
outerPath = holes[outer];
holes.splice(outer, 1);
}
} else //or just one path
outerPath = flattenPath(selectedItem);
if (!outerPath) {
alert("Bad path");
return;
}
var dd;
var fillRGB;
try {
if (selectedItem.pathItems)
dd = selectedItem.pathItems[0].fillColor
else
if (!selectedItem.filled) throw "not filled"
else
dd = selectedItem.fillColor
fillRGB = getRGBFromColor(dd);
} catch (e) {
trace(e)
fillRGB = [255, 255, 255]
}
COL = COL || fillRGB
var pathA = cutHolesInPath(outerPath, holes)
var points = [];
var rnd = NUM_POINTS;
for (var i = 0; i < rnd; i++) {
var B = selectedItem.geometricBounds;
var x = B[0] + Math.random() * (B[2] - B[0]);
var y = B[1] + Math.random() * (B[3] - B[1]);
if (pointInsidePoly([x, y], pathA)) {
points.push([x, y])
}
}
points = points.concat(pathA)
// Triangulate the points using Delaunay triangulation
var triangles = Delaunay.triangulate(points);
// Create a new layer for the triangulated shape
//change data format
var triangles2 = [];
for (var i = 0; i < triangles.length; i += 3) {
var triangle = [triangles[i], triangles[i + 1], triangles[i + 2]];
triangles2.push(triangle);
}
drawTriangles2(triangles2, points, pathA)
}
/////////////////////////////////// geom
//132532
function drawTriangles2(triangles, points,outerPath) {
var layer = doc.layers.add();
layer.name = "Triangulated Shape";
// Construct a map from point indices to arrays of adjacent triangles
// indexas - taskas, taskas turi masyva trikampiu kurie eina per ji
var adj = {};
for (var i = 0; i < triangles.length; i++) {
//kampu taskai
var a = triangles[i][0];
var b = triangles[i][1];
var c = triangles[i][2];
//jei kampas neturi dezutes, sukuriam jam
if (!adj[a]) adj[a] = [];
if (!adj[b]) adj[b] = [];
if (!adj[c]) adj[c] = [];
//i ta kampa padedam trikampio nr
adj[a].push(i);
adj[b].push(i);
adj[c].push(i);
}
var processedPoints = {}
var processedTriangles = {}
var l = points.length;
//::::::::::: FAUX SHADOW
for (var i = 0; i < l; i++) {
var toContinue = false;
//pick random point
var p = ~~(Math.random() * l);
if (processedPoints[p])
continue;
processedPoints[p] = true;
//kazkur bugas, nzn, jau velu krc
if (!adj[p]) continue;
//check all triangles around that point, make sure all unprocessed
for (var j = 0; j < adj[p].length; j++) {
var triangle = triangles[adj[p][j]];
//even one triangle processed, we break out
if (processedTriangles[triangle]) {
toContinue = true
break;
}
//::::::::: uncomment bellow for consistant shadows, } must be uncommented too
// }
// if (toContinue) continue;
// //check all triangles aroudn that point again
// for (var j = 0; j < adj[p].length; j++) {
// //check all triangles aroudn that point
// var triangle = triangles[adj[p][j]];
//::::::::: end uncomment
processedTriangles[triangle] = true;
var a = triangle[0];
var b = triangle[1];
var c = triangle[2];
var v = points[p];
var trianglePoints = [points[a], points[b], points[c]]
var cc = calculateTriangleCentroid(trianglePoints);
if (!pointInsidePoly(cc, outerPath))
continue;
var angle = Math.atan2(cc[1] - v[1], cc[0] - v[0])
angle = Math.abs(angle)
trianglePoints.push(trianglePoints[0]);
drawOneTriangle(trianglePoints, angle, layer)
}
}
//::::::: REMAINING TRIANGLES
//return;
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
if (processedTriangles[triangle])
continue;
var a = triangle[0];
var b = triangle[1];
var c = triangle[2];
var trianglePoints = [points[a], points[b], points[c]]
var cc = calculateTriangleCentroid(trianglePoints);
if (!pointInsidePoly(cc, outerPath))
continue;
trianglePoints.push(trianglePoints[0]);
drawOneTriangle(trianglePoints, Math.random() * 2, layer)
}
}
function drawOneTriangle(trianglePoints, angle, layer, dbg) {
var drawnPath = doc.pathItems.add();
drawnPath.setEntirePath(trianglePoints);
variateOneLIGHTNESS(drawnPath, [HUE_VAR, SAT_VAR, -angle * LIGHT_VAR], COL)
drawnPath.stroked = true;
drawnPath.strokeWidth = .01
drawnPath.moveToEnd(layer);
}
function setGradient(cell, pathItem, center) {
// Create a new gradient fill
var gc = getCellCenter(cell)
var cx = center[0] - gc[0];
var cy = center[1] - gc[1];
var gradient = doc.gradients.add();
gradient.type = GradientType.RADIAL;
// set the center point and radius of the gradient
gradient.gradientStops[0].rampPoint = 0;
gradient.gradientStops[1].rampPoint = 100;
gradient.gradientStops[0].midPoint = 80;
gradient.gradientStops[1].midPoint = 80;
var col0 = new RGBColor();
col0.green = 0, col0.blue = 0, col0.red = 0;
var col1 = new RGBColor();
//col1.green=255,col1.blue=255,col1.red=255;
col1.green = 155, col1.blue = 155, col1.red = 155;
gradient.gradientStops[0].color = col1;
gradient.gradientStops[1].color = col0;
// // translate the gradient origin to [cx, cy]
// var tx = cx - gradient.gradientStops[0].rampPoint / 100 * (cx - gradient.gradientStops[1].rampPoint);
// var ty = cy - gradient.gradientStops[0].rampPoint / 100 * (cy - gradient.gradientStops[1].rampPoint);
// gradient.gradientTransform = new Matrix(1, 0, 0, 1, cx, cy);
// trace(tx)
// Apply the gradient fill to the path
var gc = new GradientColor();
gc.gradient = gradient;
//gc.matrix=concatenateTranslationMatrix(gc.matrix,cx,cy)
//gc.origin=center
var moveMatrix = getTranslationMatrix(cx, cy);
var rotateMatrix = concatenateRotationMatrix(moveMatrix, 0);
var totalMatrix = concatenateScaleMatrix(rotateMatrix, 110, 110);
pathItem.fillColor = gc;
pathItem.fillOverprint = false
pathItem.transform(totalMatrix, false, false, true, false, 0, Transformation.CENTER);
}
function drawPath(a, n) {
var drawnPath = doc.pathItems.add();
try {
drawnPath.setEntirePath(a);
} catch (e) {
}
drawnPath.stroked = true;
drawnPath.strokeColor = doc.swatches[n].color
}
function setGradient2(pathItem, center) {
// Create a new gradient fill
var gradient = doc.gradients.add();
gradient.type = GradientType.RADIAL; // Set the gradient type to radial
gradient.gradientOrigin = [center[1], center[0]]
// Set the center of the gradient to [cx, cy]
var centerColor = gradient.gradientStops.add();
centerColor.color = doc.defaultFillColor; // Use the default fill color
centerColor.location = 0;
// Set the outer edge of the gradient to the maximum distance of the path from the center
var outerColor = gradient.gradientStops.add();
outerColor.color = doc.defaultFillColor; // Use the default fill color
outerColor.location = 1;
// Apply the gradient fill to the path
var color_of_gradient = new GradientColor();
color_of_gradient.gradient = gradient;
pathItem.fillColor = color_of_gradient;
}
function drawPath(a, n) {
var drawnPath = doc.pathItems.add();
try {
drawnPath.setEntirePath(a);
} catch (e) {
}
drawnPath.stroked = true;
drawnPath.strokeColor = doc.swatches[n].color
}
function curve4(x1, y1, //Anchor1
x2, y2, //Control1
x3, y3, //Control2
x4, y4, //Anchor2
nSteps // Flattening value
) {
var pointList = new Array();
var dx1 = x2 - x1;
var dy1 = y2 - y1;
var dx2 = x3 - x2;
var dy2 = y3 - y2;
var dx3 = x4 - x3;
var dy3 = y4 - y3;
var subdiv_step = 1.0 / (nSteps + 1);
var subdiv_step2 = subdiv_step * subdiv_step;
var subdiv_step3 = subdiv_step * subdiv_step * subdiv_step;
var pre1 = 3.0 * subdiv_step;
var pre2 = 3.0 * subdiv_step2;
var pre4 = 6.0 * subdiv_step2;
var pre5 = 6.0 * subdiv_step3;
var tmp1x = x1 - x2 * 2.0 + x3;
var tmp1y = y1 - y2 * 2.0 + y3;
var tmp2x = (x2 - x3) * 3.0 - x1 + x4;
var tmp2y = (y2 - y3) * 3.0 - y1 + y4;
var fx = x1;
var fy = y1;
var dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3;
var dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3;
var ddfx = tmp1x * pre4 + tmp2x * pre5;
var ddfy = tmp1y * pre4 + tmp2y * pre5;
var dddfx = tmp2x * pre5;
var dddfy = tmp2y * pre5;
var step = nSteps;
pointList.push([x1, y1]); // Start Here
while (step--) {
fx += dfx;
fy += dfy;
dfx += ddfx;
dfy += ddfy;
ddfx += dddfx;
ddfy += dddfy;
pointList.push([fx, fy]);
}
// pointList.push ([x4, y4]); // Last step must go exactly to x4, y4
return pointList;
}
function flattenPath(obj) {
var newpath = new Array();
var curveList;
var pt, nextpt;
var isFlattened = false;
if (!obj.hasOwnProperty("pathPoints"))
return null;
for (pt = 0; pt < obj.pathPoints.length; pt++) {
nextpt = pt + 1;
if (nextpt == obj.pathPoints.length)
nextpt = 0;
if (obj.pathPoints[pt].anchor[0] == obj.pathPoints[pt].rightDirection[0] && obj.pathPoints[pt].anchor[1] == obj.pathPoints[pt].rightDirection[1] &&
obj.pathPoints[nextpt].anchor[0] == obj.pathPoints[nextpt].leftDirection[0] && obj.pathPoints[nextpt].anchor[1] == obj.pathPoints[nextpt].leftDirection[1]) {
newpath.push(obj.pathPoints[pt].anchor);
} else {
isFlattened = true;
curveList = curve4(obj.pathPoints[pt].anchor[0], obj.pathPoints[pt].anchor[1],
obj.pathPoints[pt].rightDirection[0], obj.pathPoints[pt].rightDirection[1],
obj.pathPoints[nextpt].leftDirection[0], obj.pathPoints[nextpt].leftDirection[1],
obj.pathPoints[nextpt].anchor[0], obj.pathPoints[nextpt].anchor[1],
2);
newpath = newpath.concat(curveList);
}
}
// Make path round
// newpath.push (newpath[0]);
return newpath;
}
function removeWalls(current, neighbor) {
var c0 = getCellCenter(current);
var c1 = getCellCenter(neighbor);
drawPath([c0, c1], 6)
}
function drawVoronoi(cells, centers, points, doc) {
// Create a new layer to draw the Voronoi cells on
var layer = doc.layers.add();
layer.name = "Voronoi Diagram";
// Loop through each cell and draw its edges and fill
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
// Create a new path object for the cell's edges
var edges = doc.pathItems.add();
edges.filled = false;
edges.stroked = true;
edges.strokeWidth = 0.5;
cell.push(cell[0])
edges.setEntirePath(cell);
// setGradient(cell, edges, points[centers[i]])
}
}
// Helper function to compute the circumcenter of a triangle
function circumcenter(a, b, c) {
// Define the coordinates of the points
var ax = a[0], ay = a[1];
var bx = b[0], by = b[1];
var cx = c[0], cy = c[1];
// Define the distances between the points
var a2 = ax * ax + ay * ay;
var b2 = bx * bx + by * by;
var c2 = cx * cx + cy * cy;
// Define the denominator of the formula
var d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
// Define the coordinates of the circumcenter
var ux = ((a2 * (by - cy) + b2 * (cy - ay) + c2 * (ay - by)) / d);
var uy = ((a2 * (cx - bx) + b2 * (ax - cx) + c2 * (bx - ax)) / d);
// Return the coordinates of the circumcenter as an array
return [[ux, uy], d];
}
function sortCellPaths(cells) {
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
// Sort the points in the cell by their angle with respect to the cell center
var center = getCellCenter(cell);
cell.sort(function (a, b) {
var angleA = Math.atan2(a[1] - center[1], a[0] - center[0]);
var angleB = Math.atan2(b[1] - center[1], b[0] - center[0]);
return angleA - angleB;
});
}
return cells
}
// Helper function to compute the center of a Voronoi cell
//not corect! just basic center of path
function getCellCenter(cell) {
var sumX = 0, sumY = 0;
for (var i = 0; i < cell.length; i++) {
sumX += cell[i][0];
sumY += cell[i][1];
}
return [sumX / cell.length, sumY / cell.length];
}
//from Jongware
function cutHolesInPath(path, holes) {
if (getWinding(path) < 0)
path.reverse();
// Remove holes by joining them with the outer edge
if (holes.length) {
for (hh = 0; hh < holes.length; hh++) {
var h = holes[hh];
if (getWinding(h) > 0)
h.reverse();
var maxpt = 0;
for (i = 1; i < h.length; i++) {
if (h[i][0] > h[maxpt][0] || (h[i][0] == h[maxpt][0] && h[i][1] < h[maxpt][1]))
maxpt = i;
}
while (maxpt > 0) {
h.push(h.shift());
maxpt--;
}
}
holes.sort(function (a, b) { if (a[0][0] > b[0][0]) return -1; if (a[0][0] < b[0][0]) return 1; return (a[0][1] < b[0][1]) ? 1 : -1; });
for (hh = 0; hh < holes.length; hh++) {
var h = holes[hh];
var maxpt = 0;
for (i = 1; i < h.length; i++)
if (h[i][0] > h[maxpt][0] || (h[i][0] == h[maxpt][0] && h[i][1] < h[maxpt][1]))
maxpt = i;
var d2 = null;
var closestpt;
for (i = 0; i < path.length; i++) {
if (path[i][0] > h[maxpt][0]) {
if (d2 == null) {
d2 = ClosestPointOnLine(h[maxpt], [path[i], path[(i + 1) % path.length]])[1];
closestpt = i;
} else {
var dd2 = ClosestPointOnLine(h[maxpt], [path[i], path[(i + 1) % path.length]])[1];
if (dd2 < d2) {
d2 = dd2;
closestpt = i;
}
}
}
}
path.splice(closestpt, 0, [path[closestpt][0], path[closestpt][1] + 0.1]);
closestpt++;
h.splice(maxpt, 0, [h[maxpt][0], h[maxpt][1]]);
h[maxpt][1] -= 0.1;
for (var i = maxpt; i >= 0; i--) {
path.splice(closestpt, 0, h[i]);
}
for (var i = h.length - 1; i > maxpt; i--) {
path.splice(closestpt, 0, h[i]);
}
}
}
return path
}
function getWinding(path) {
// Return area of a simple (ie. non-self-intersecting) polygon.
// Will be negative for counterclockwise winding.
var i, next;
var accum = 0;
for (i = 0; i < path.length - 1; i++) {
next = i + 1;
accum += path[next][0] * path[i][1] - path[i][0] * path[next][1];
}
next = 0;
accum += path[next][0] * path[i][1] - path[i][0] * path[next][1];
return accum / 2;
}
function calculateTriangleCentroid(tri) {
//util_inspect_properties(tri)
var centerX = (tri[0][0] + tri[1][0] + tri[2][0]) / 3;
var centerY = (tri[0][1] + tri[1][1] + tri[2][1]) / 3;
return [centerX, centerY];
}
function pointInsidePoly(pt, poly) {
for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1] < poly[i][1]))
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
&& (c = !c);
return c;
}
function drawTriangles(triangles, points, outerPath) {
var layer = doc.layers.add();
layer.name = "Triangulated Shape";
for (var i = 0; i < triangles.length; i += 3) {
var triangle = [[points[triangles[i]][0], points[triangles[i]][1]],
[points[triangles[i + 1]][0], points[triangles[i + 1]][1]],
[points[triangles[i + 2]][0], points[triangles[i + 2]][1]],
[points[triangles[i]][0], points[triangles[i]][1]]
]
if (pointInsidePoly(calculateTriangleCentroid(triangle), outerPath)) {
var drawnPath = doc.pathItems.add();
drawnPath.setEntirePath(triangle);
//drawnPath.filled = true;
//drawnPath.fillColor = new RGBColor(255, 0, 0);
variateOneLIGHTNESS(drawnPath, [0, 0, -Math.random() * 100], [255, 255, 255])
drawnPath.stroked = true;
drawnPath.moveToEnd(layer);
}
}
}
function linePathIntersect(line, path) {
var x1 = line[0][0];
var y1 = line[0][1];
var x2 = line[1][0];
var y2 = line[1][1];
for (var i = 0; i < path.length - 1; i++) {
var x3 = path[i][0];
var y3 = path[i][1];
var x4 = path[i + 1][0];
var y4 = path[i + 1][1];
var den = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
if (den == 0) continue;
var ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / den;
var ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / den;
if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) {
return true;
}
}
return false;
}
function getPointsOfPath(selectedItem) {
var pathA = [];
for (var i = 0; i < selectedItem.pathPoints.length; i++) {
var x = selectedItem.pathPoints[i].anchor[0];
var y = selectedItem.pathPoints[i].anchor[1];
pathA.push([x, y]);
}
return pathA;
}
////////maze
function getAdjacentCells(cells) {
var adj = {};
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
for (var j = 0; j < cell.length; j++) {
var point = cell[j];
if (!adj[point]) adj[point] = [];
//keeps index of cells
adj[point].push(i);
}
}
return adj;
}
function generateMaze(neighbours, startCellIndex) {
var currentCell = neighbours[startCellIndex];
visited[startCellIndex] = true;
for (var i = 0; i < currentCell.length; i++) {
var neighbourIndex = currentCell[i];
// if the neighbour hasn't been visited, add it to the list of unvisited neighbours
if (!visited[neighbourIndex]) {
if (Math.random() > .4) {
generateMaze(neighbours, neighbourIndex)
removeWalls(cells[startCellIndex], cells[neighbourIndex]);
}
}
}
}
function getNeighbouringCells(cells) {
var neighbours = {};
// get cells adjacent to each vertex
var adjacentCells = getAdjacentCells(cells);
// iterate over each cell
for (var i = 0; i < cells.length; i++) {
var cell = cells[i];
var cellNeighbours = [];
// check each vertex of the current cell
for (var j = 0; j < cell.length; j++) {
var vertex = cell[j];
// iterate over adjacent cells for the current vertex
for (var k = 0; k < adjacentCells[vertex].length; k++) {
var adjacentCellIndex = adjacentCells[vertex][k];
// add the adjacent cell index to the current cell's neighbours
if (adjacentCellIndex !== i && cellNeighbours.indexOf(adjacentCellIndex) === -1) {
cellNeighbours.push(adjacentCellIndex);
}
}
}
neighbours[i] = cellNeighbours;
}
return neighbours;
}
function generateMaze2(neighbours, startCellIndex) {
var visited = {};
var stack = [startCellIndex];
var maze = {};
// mark the starting cell as visited
visited[startCellIndex] = true;
// set previous cell to starting cell
var prevIndex = startCellIndex;
// loop until the stack is empty
while (stack.length > 0) {
var currentIndex = stack[stack.length - 1];
var currentCell = neighbours[currentIndex];
var unvisitedNeighbours = [];
// check each neighbouring cell
for (var i = 0; i < currentCell.length; i++) {
var neighbourIndex = currentCell[i];
// if the neighbour hasn't been visited, add it to the list of unvisited neighbours
if (!visited[neighbourIndex]) {
unvisitedNeighbours.push(neighbourIndex);
}
}
// if there are unvisited neighbours, pick one at random and remove the wall between the current cell and the chosen neighbour
if (unvisitedNeighbours.length > 0) {
var chosenIndex = Math.floor(Math.random() * unvisitedNeighbours.length);
var chosenCell = unvisitedNeighbours[chosenIndex];
// remove the wall between the current cell and the chosen neighbour
if (!maze[currentIndex]) {
maze[currentIndex] = [];
}
removeWalls(cells[currentIndex], cells[chosenCell]);
if (!maze[chosenCell]) {
maze[chosenCell] = [];
}
maze[currentIndex].push(chosenCell);
maze[chosenCell].push(currentIndex);
// mark the chosen neighbour as visited and add it to the stack
visited[chosenCell] = true;
stack.push(chosenCell);
// update previous cell
prevIndex = currentIndex;
} else {
// backtracking: if there are no unvisited neighbours, remove the current cell from the stack and continue with the previous cell
stack.pop();
currentIndex = prevIndex;
}
}
return maze;
}
function drawTriangle(i) {
var triangle =
[[points[triangles2[i][0]][0], points[triangles2[i][0]][1]],
[points[triangles2[i][1]][0], points[triangles2[i][1]][1]],
[points[triangles2[i][2]][0], points[triangles2[i][2]][1]],
[points[triangles2[i][0]][0], points[triangles2[i][0]][1]]
]
var drawnPath = doc.pathItems.add();
drawnPath.setEntirePath(triangle);
drawnPath.stroked = true;
}
/////////////////////////////////// misc
Array.prototype.indexOf = function (searchElement, fromIndex) {
var startIndex = fromIndex || 0;
var length = this.length;
for (var i = startIndex; i < length; i++) {
if (this[i] == searchElement) {
return i;
}
}
return -1;
};
function clearConsole() {
return;
if (app.name === "ExtendScript Toolkit") {
app.clc();
} else {
var estApp = BridgeTalk.getSpecifier("estoolkit");
if (estApp) {
var bt = new BridgeTalk;
bt.target = estApp;
bt.body = "app.clc()";
bt.send();
}
}
}
function util_inspect_properties(f) {
$.writeln(f.reflect.name);
var props = f.reflect.properties;
var array = [];
for (var i = 0; i < props.length; i++)
try {
array.push(props[i].name + ": " + f[props[i].name])
} catch (_) { }
array.sort();
$.writeln(array.join("\r"));
}
function traceON(v) {
return;
trace(JSON.stringify(v))
}
function trace() {
return;
var s = "";
for (var i = 0; i < arguments.length; i++) {
s += arguments[i] + " "
}
$.writeln(s);
}
// Compute the distance from segment Line to Pt
// Returns [ Point, Distance ]
function ClosestPointOnLine(pt, line) {
var X1 = line[0][0], Y1 = line[0][1];
var X2 = line[1][0], Y2 = line[1][1];
var px = pt[0], py = pt[1];
var dx = X2 - X1;
var dy = Y2 - Y1;
var nx, ny;
if (dx == 0 && dy == 0) {
// It's a point not a line segment.
// dx = px - X1
// dy = py - Y1
// distance = Sqr(dx * dx + dy * dy)
nx = X1;
ny = Y1;
} else {
// Calculate the t that minimizes the distance.
var t = ((px - X1) * dx + (py - Y1) * dy) / (dx * dx + dy * dy);
// See if this represents one of the segment's
// end points or a point in the middle.
if (t <= 0) {
nx = X1;
ny = Y1;
} else if (t >= 1) {
nx = X2;
ny = Y2;
} else {
nx = X1 + t * dx;
ny = Y1 + t * dy;
}
}
dx = px - nx;
dy = py - ny;
return [[nx, ny], Math.sqrt(dx * dx + dy * dy)];
}
function getCurrentColors() {
var doc = app.activeDocument;
var currentColors = {};
var dd
var fillRGB
try {
dd = doc.defaultFillColor
fillRGB = getRGBFromColor(dd);
} catch (e) {
fillRGB = [255, 255, 255]
}
var fillRGBColor = getRGBColorFromArray(fillRGB);
currentColors.fill = fillRGBColor;
//!!!!!!!!!!! add try/cacth
var strokeRGB = getRGBFromColor(doc.defaultStrokeColor);
var strokeRGBColor = getRGBColorFromArray(strokeRGB);
currentColors.stroke = strokeRGBColor;
return currentColors;
}
function getRGBFromColor(color) {
if (color.typename == "RGBColor") {
return [color.red, color.green, color.blue];
} else if (color.typename == "GrayColor") {
return [color.gray, color.gray, color.gray];
} else if (color.typename == "CMYKColor") {
var cyan = color.cyan / 100;
var magenta = color.magenta / 100;
var yellow = color.yellow / 100;
var black = color.black / 100;
var red = 1 - Math.min(1, cyan * (1 - black) + black);
var green = 1 - Math.min(1, magenta * (1 - black) + black);
var blue = 1 - Math.min(1, yellow * (1 - black) + black);
return [Math.round(red * 255), Math.round(green * 255), Math.round(blue * 255)];
} else {
return [0, 0, 0];
}
}
function getRGBColorFromArray(rgbArray) {
var red = rgbArray[0];
var green = rgbArray[1];
var blue = rgbArray[2];
red = range(red, 0, 255);
green = range(green, 0, 255);
blue = range(blue, 0, 255);
var rgbColor = new RGBColor();
rgbColor.red = red;
rgbColor.green = green;
rgbColor.blue = blue;
return rgbColor;
}
function range(v, d, u) {
if (v > u) v = u;
if (v < d) v = d;
return v;
}
function rgbToHsl(color) {
var r = color.red / 255;
var g = color.green / 255;
var b = color.blue / 255;
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0;
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return {
hue: Math.round(h * 360),
saturation: Math.round(s * 100),
lightness: Math.round(l * 100)
};
}
function hslToRgb(h, s, l) {
var chroma = (1 - Math.abs((2 * l / 100) - 1)) * (s / 100);
var hueSegment = h / 60;
var x = chroma * (1 - Math.abs((hueSegment % 2) - 1));
var r1, g1, b1;
if (hueSegment >= 0 && hueSegment < 1) {
r1 = chroma;
g1 = x;
b1 = 0;
} else if (hueSegment >= 1 && hueSegment < 2) {
r1 = x;
g1 = chroma;
b1 = 0;
} else if (hueSegment >= 2 && hueSegment < 3) {
r1 = 0;
g1 = chroma;
b1 = x;
} else if (hueSegment >= 3 && hueSegment < 4) {
r1 = 0;
g1 = x;
b1 = chroma;
} else if (hueSegment >= 4 && hueSegment < 5) {
r1 = x;
g1 = 0;
b1 = chroma;
} else {
r1 = chroma;
g1 = 0;
b1 = x;
}
var m = (l / 100) - (chroma / 2);
var r = Math.round((r1 + m) * 255);
var g = Math.round((g1 + m) * 255);
var b = Math.round((b1 + m) * 255);
return [r, g, b];
}
function variateOneLIGHTNESS(p, h, cc) {
c = p.fillColor;
c = getRGBFromColor(c);
///!!!
c = getRGBColorFromArray(cc ? cc : c);
c = rgbToHsl(c);
p.filled = true;
p.fillColor = getRGBColorFromArray(hslToRgb(c.hue + h[0] * Math.random() - h[0] / 2, c.saturation + h[1] * Math.random() - h[1] / 2, c.lightness + h[2]));
}
var Delaunay;
(function() {
"use strict";
var EPSILON = 1.0 / 1048576.0;
function supertriangle(vertices) {
var xmin = Number.POSITIVE_INFINITY,
ymin = Number.POSITIVE_INFINITY,
xmax = Number.NEGATIVE_INFINITY,
ymax = Number.NEGATIVE_INFINITY,
i, dx, dy, dmax, xmid, ymid;
for(i = vertices.length; i--; ) {
if(vertices[i][0] < xmin) xmin = vertices[i][0];
if(vertices[i][0] > xmax) xmax = vertices[i][0];
if(vertices[i][1] < ymin) ymin = vertices[i][1];
if(vertices[i][1] > ymax) ymax = vertices[i][1];
}
dx = xmax - xmin;
dy = ymax - ymin;
dmax = Math.max(dx, dy);
xmid = xmin + dx * 0.5;
ymid = ymin + dy * 0.5;
return [
[xmid - 20 * dmax, ymid - dmax],
[xmid , ymid + 20 * dmax],
[xmid + 20 * dmax, ymid - dmax]
];
}
function circumcircle(vertices, i, j, k) {
var x1 = vertices[i][0],
y1 = vertices[i][1],
x2 = vertices[j][0],
y2 = vertices[j][1],
x3 = vertices[k][0],
y3 = vertices[k][1],
fabsy1y2 = Math.abs(y1 - y2),
fabsy2y3 = Math.abs(y2 - y3),
xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;
/* Check for coincident points */
if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
throw new Error("Eek! Coincident points!");
if(fabsy1y2 < EPSILON) {
m2 = -((x3 - x2) / (y3 - y2));
mx2 = (x2 + x3) / 2.0;
my2 = (y2 + y3) / 2.0;
xc = (x2 + x1) / 2.0;
yc = m2 * (xc - mx2) + my2;
}
else if(fabsy2y3 < EPSILON) {
m1 = -((x2 - x1) / (y2 - y1));
mx1 = (x1 + x2) / 2.0;
my1 = (y1 + y2) / 2.0;
xc = (x3 + x2) / 2.0;
yc = m1 * (xc - mx1) + my1;
}
else {
m1 = -((x2 - x1) / (y2 - y1));
m2 = -((x3 - x2) / (y3 - y2));
mx1 = (x1 + x2) / 2.0;
mx2 = (x2 + x3) / 2.0;
my1 = (y1 + y2) / 2.0;
my2 = (y2 + y3) / 2.0;
xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
yc = (fabsy1y2 > fabsy2y3) ?
m1 * (xc - mx1) + my1 :
m2 * (xc - mx2) + my2;
}
dx = x2 - xc;
dy = y2 - yc;
return {i: i, j: j, k: k, x: xc, y: yc, r: dx * dx + dy * dy};
}
function dedup(edges) {
var i, j, a, b, m, n;
for(j = edges.length; j; ) {
b = edges[--j];
a = edges[--j];
for(i = j; i; ) {
n = edges[--i];
m = edges[--i];
if((a === m && b === n) || (a === n && b === m)) {
edges.splice(j, 2);
edges.splice(i, 2);
break;
}
}
}
}
Delaunay = {
triangulate: function(vertices, key) {
var n = vertices.length,
i, j, indices, st, open, closed, edges, dx, dy, a, b, c;
/* Bail if there aren't enough vertices to form any triangles. */
if(n < 3)
return [];
/* Slice out the actual vertices from the passed objects. (Duplicate the
* array even if we don't, though, since we need to make a supertriangle
* later on!) */
vertices = vertices.slice(0);
if(key)
for(i = n; i--; )
vertices[i] = vertices[i][key];
/* Make an array of indices into the vertex array, sorted by the
* vertices' x-position. Force stable sorting by comparing indices if
* the x-positions are equal. */
indices = new Array(n);
for(i = n; i--; )
indices[i] = i;
indices.sort(function(i, j) {
var diff = vertices[j][0] - vertices[i][0];
return diff !== 0 ? diff : i - j;
});
/* Next, find the vertices of the supertriangle (which contains all other
* triangles), and append them onto the end of a (copy of) the vertex
* array. */
st = supertriangle(vertices);
vertices.push(st[0], st[1], st[2]);
/* Initialize the open list (containing the supertriangle and nothing
* else) and the closed list (which is empty since we havn't processed
* any triangles yet). */
open = [circumcircle(vertices, n + 0, n + 1, n + 2)];
closed = [];
edges = [];
/* Incrementally add each vertex to the mesh. */
for(i = indices.length; i--; edges.length = 0) {
c = indices[i];
/* For each open triangle, check to see if the current point is
* inside it's circumcircle. If it is, remove the triangle and add
* it's edges to an edge list. */
for(j = open.length; j--; ) {
/* If this point is to the right of this triangle's circumcircle,
* then this triangle should never get checked again. Remove it
* from the open list, add it to the closed list, and skip. */
dx = vertices[c][0] - open[j].x;
if(dx > 0.0 && dx * dx > open[j].r) {
closed.push(open[j]);
open.splice(j, 1);
continue;
}
/* If we're outside the circumcircle, skip this triangle. */
dy = vertices[c][1] - open[j].y;
if(dx * dx + dy * dy - open[j].r > EPSILON)
continue;
/* Remove the triangle and add it's edges to the edge list. */
edges.push(
open[j].i, open[j].j,
open[j].j, open[j].k,
open[j].k, open[j].i
);
open.splice(j, 1);
}
/* Remove any doubled edges. */
dedup(edges);
/* Add a new triangle for each edge. */
for(j = edges.length; j; ) {
b = edges[--j];
a = edges[--j];
open.push(circumcircle(vertices, a, b, c));
}
}
/* Copy any remaining open triangles to the closed list, and then
* remove any triangles that share a vertex with the supertriangle,
* building a list of triplets that represent triangles. */
for(i = open.length; i--; )
closed.push(open[i]);
open.length = 0;
for(i = closed.length; i--; )
if(closed[i].i < n && closed[i].j < n && closed[i].k < n)
open.push(closed[i].i, closed[i].j, closed[i].k);
/* Yay, we're done! */
return open;
},
contains: function(tri, p) {
/* Bounding box test first, for quick rejections */
if (p[0] < tri[0][0] && p[0] < tri[1][0] && p[0] < tri[2][0] ||
p[0] > tri[0][0] && p[0] > tri[1][0] && p[0] > tri[2][0] ||
p[1] < tri[0][1] && p[1] < tri[1][1] && p[1] < tri[2][1] ||
p[1] > tri[0][1] && p[1] > tri[1][1] && p[1] > tri[2][1])
return null;
var a = tri[1][0] - tri[0][0],
b = tri[2][0] - tri[0][0],
c = tri[1][1] - tri[0][1],
d = tri[2][1] - tri[0][1],
i = a * d - b * c;
/* Degenerate tri. */
if (i === 0.0)
return null;
var u = (d * (p[0] - tri[0][0]) - b * (p[1] - tri[0][1])) / i,
v = (a * (p[1] - tri[0][1]) - c * (p[0] - tri[0][0])) / i;
/* If we're outside the tri, fail */
if (u < 0.0 || v < 0.0 || (u + v) > 1.0)
return null;
return [u, v];
},
};
if(typeof module !== "undefined")
module.exports = Delaunay;
})();
main()
})();