1326 lines
36 KiB
JavaScript
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()
|
|
|
|
})();
|
|
|