xxxxxxxxxx
let polys;
let S, SD, boundaryPoints;
let tryInc, tries;
const SCL = 3, MAR = 20;
const pal = ["darkorange", "darkred", "cyan", "steelblue"]
let svgGrs, svgStr;
function setup() {
createCanvas(210 * SCL, 297 * SCL);
noFill();
// boundary for clipping
boundaryPoints = [
{ x: MAR, y: MAR },
{ x: width-MAR, y: MAR },
{ x: width-MAR, y: height-MAR },
{ x: MAR, y: height-MAR },
]
tryInc = 50;
tries = tryInc;
S = min(width, height) * 0.45;
SD = 1.15;
svgGrps = []; for (let i = 0; i < pal.length; i++) svgGrps[i] = "";
polys = []
background(32);
loop();
}
function draw() {
createPoly();
/*
for (let poly of polys) {
beginShape()
for (const pt of poly) vertex(pt[0], pt[1])
endShape(CLOSE)
}
*/
}
function createPoly(tr = 100) {
for (let i = 0; i < tr; i++) {
const cx = random(0.1, 0.9) * width;
const cy = random(0.1, 0.9) * height;
const sz = S; // random(0.5, 1) * S;
const vec = createVector(sz, 0).rotate(-PI/6);
const typ = ~~(random(3));
let newPoly;
if (typ === 0) newPoly = [[cx-vec.x/2, cy], [cx-vec.x/2, cy-vec.y], [cx+vec.x/2, cy], [cx+vec.x/2, cy+vec.y]];
if (typ === 1) newPoly = [[cx+vec.x/2, cy], [cx+vec.x/2, cy-vec.y], [cx-vec.x/2, cy], [cx-vec.x/2, cy+vec.y]];
if (typ === 2) newPoly = [[cx, cy-vec.y], [cx+vec.x, cy], [cx, cy+vec.y], [cx-vec.x, cy]]
if (!intersectsPolys(newPoly)) {
polys.push(newPoly);
const grId = ~~random(pal.length);
stroke(pal[grId]);
/*
beginShape()
for (const pt of newPoly) vertex(pt[0], pt[1])
endShape(CLOSE)
*/
svgStr = "";
for (let i = 0; i < newPoly.length; i++) {
const p1 = newPoly[i];
const p2 = newPoly[(i+1)%newPoly.length];
clipLine({x: p1[0], y: p1[1]}, {x: p2[0], y: p2[1]}, boundaryPoints)
}
svgGrps[grId] += svgStr; // store svg in group
}
tries--;
if (tries < 0) {
S *= 0.67;
tryInc *= 2;
tries = tryInc;
/*
S /= SD;
SD = lerp(SD, 1, 0.065);
*/
console.log(polys.length, tries, tryInc, S, SD)
if (S < 5 || SD < 1.000005) noLoop();
}
}
}
function mouseClicked() {
if (mouseButton !== RIGHT && mouseX > 0 && mouseX < width) {
setup();
}
}
function keyPressed() {
if (key == "s") {
// console.log(svgGrps);
let svgStr = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">\n`;
for (let i = 0; i < svgGrps.length; i++) {
svgStr += `<g fill="none" stroke="${pal[i]}" stroke-width="1">\n`;
svgStr += svgGrps[i];
svgStr += `</g>\n`;
}
svgStr += `</svg>`;
save(svgStr.split("\n"), "epi_iso.svg.txt");
}
}
function intersectsPolys(newPoly) {
let intersects = false;
for (const other of polys) {
// test if newPoly is not in other
for (const pt of newPoly) {
intersects = intersects || pointInPolygon(other, pt);
}
// test if other is not in newPoly
for (const pt of other) {
intersects = intersects || pointInPolygon(newPoly, pt);
}
// test if line segments intersects
for (let i = 0; i < other.length; i++) {
for (let j = 0; j < newPoly.length; j++) {
const p1 = other[i];
const p2 = other[(i+1)%other.length];
const p3 = newPoly[j];
const p4 = newPoly[(j+1)%newPoly.length];
const x1 = p1[0]
const y1 = p1[1]
const x2 = p2[0]
const y2 = p2[1]
const x3 = p3[0]
const y3 = p3[1]
const x4 = p4[0]
const y4 = p4[1]
if (intersectLines(x1, y1, x2, y2, x3, y3, x4, y4)) {
intersects = true;
break;
}
}
}
if (intersects) break;
}
return intersects
}
/*
Line intercept math by Paul Bourke http://paulbourke.net/geometry/pointlineplane/
- Returns the coordinate of the intersection point
- Returns FALSE if the lines don't intersect
Coordinates x1, y1, x2 and y2 designate the start and end point of the first line
Coordinates x3, y3, x4 and y4 designate the start and end point of the second line
*/
function intersectLines(x1, y1, x2, y2, x3, y3, x4, y4) {
// Check if none of the lines are of length 0
if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
return false
}
denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
// Lines are parallel
if (denominator === 0) {
return false
}
let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator
// is the intersection along the segments
if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
return false
}
// Return a object with the x and y coordinates of the intersection
let x = x1 + ua * (x2 - x1)
let y = y1 + ua * (y2 - y1)
return {x, y}
}
/**
* Performs the even-odd-rule Algorithm (a raycasting algorithm) to find out whether a point is in a given polygon.
* This runs in O(n) where n is the number of edges of the polygon.
*
* @param {Array} polygon an array representation of the polygon where polygon[i][0] is the x Value of the i-th point and polygon[i][1] is the y Value.
* @param {Array} point an array representation of the point where point[0] is its x Value and point[1] is its y Value
* @return {boolean} whether the point is in the polygon (not on the edge, just turn < into <= and > into >= for that)
*/
const pointInPolygon = function (polygon, point) {
//A point is in a polygon if a line from the point to infinity crosses the polygon an odd number of times
let odd = false;
//For each edge (In this case for each point of the polygon and the previous one)
for (let i = 0, j = polygon.length - 1; i < polygon.length; i++) {
//If a line from the point into infinity crosses this edge
if (((polygon[i][1] > point[1]) !== (polygon[j][1] > point[1])) // One point needs to be above, one below our y coordinate
// ...and the edge doesn't cross our Y corrdinate before our x coordinate (but between our x coordinate and infinity)
&& (point[0] < ((polygon[j][0] - polygon[i][0]) * (point[1] - polygon[i][1]) / (polygon[j][1] - polygon[i][1]) + polygon[i][0]))) {
// Invert odd
odd = !odd;
}
j = i;
}
//If the number of crossings was odd, the point is in the polygon
return odd;
};
6
100
189.94500000000002
1.15
7
200
127.26315000000002
1.15
12
400
85.26631050000002
1.15
19
800
57.12842803500001
1.15