xxxxxxxxxx
155
let stepSize = 2;
let errorMargin = 0.01;
let filename = "contour1";
let slider;
let table;
let csvExporter;
let polygon = [];
let drawPath;
let sqr = [[0,0],
[0,100],
[100,100],
[100,0]];
function preload(){
table = loadTable('pattern.csv', 'csv', 'header');
}
function setup() {
createCanvas(400, 400);
angleMode(RADIANS);
slider = createSlider(0,60).size(width)
csvExporter = new CSVExporter(filename)
createButton('download csv').mousePressed(() => {csvExporter.saveCSV(coords, 1)}).position(20,height + 20);
noFill();
// for (let r = 0; r < table.getRowCount(); r++){
for (let r = table.getRowCount()-1; r >=0 ; r--){
if(table.get(r, 'poly') == 0){
polygon.push([ int(table.get(r, 'x'))*2 + width/2,
int(table.get(r, 'y'))*2 + height/8 ])
}
}
polygon = sanitizePath(polygon);
}
function draw() {
background(220);
drawPath = contourFill(polygon);
noStroke();
fill(255);
beginShape();
for(let i=0; i<polygon.length; i++){
vertex(polygon[i][0], polygon[i][1]);
}
endShape();
noFill();
stroke(0);
beginShape();
for(let i=0; i<frameCount%drawPath.length; i++){
vertex(drawPath[i][0], drawPath[i][1]);
}
endShape();
}
function contourFill(polygon){
// polygon = sanitizePath(polygon);
let clockDir = findClockDirection(polygon);
let contourPath = [];
contourPath = contourPath.concat(polygon);
let offset = stepSize;
while(offset < stepSize * (slider.value())){
contourPath = contourPath.concat( getOffsetPath(polygon, offset, clockDir) );
offset+=stepSize;
}
return contourPath;
}
function sanitizePath(polygon){
print(polygon);
let cleanPath = [];
for(let i=0; i<polygon.length; i++){
if(abs(polygon[i][0] - polygon[(i+1)%polygon.length][0]) < errorMargin &&
abs(polygon[i][1] - polygon[(i+1)%polygon.length][1]) < errorMargin){
continue;
}
cleanPath.push([polygon[i][0], polygon[i][1]]);
}
polygon = structuredClone(cleanPath);
cleanPath = [];
for(let i=0; i<polygon.length; i++){
let v0 = createVector( polygon[i][0] - polygon[(polygon.length+i-1)%polygon.length][0],
polygon[i][1] - polygon[(polygon.length+i-1)%polygon.length][1]);
let v1 = createVector( polygon[i][0] - polygon[(i+1)%polygon.length][0],
polygon[i][1] - polygon[(i+1)%polygon.length][1]);
if(abs(v1.angleBetween(v0) - PI) < errorMargin){
continue;
}
cleanPath.push([polygon[i][0], polygon[i][1]]);
}
print(cleanPath);
return cleanPath;
}
function findClockDirection(polygon){
// i think i wanna do/store more stuff here so i dont need to do it again in getOffsetPath, including storing angles for each point and their direction vector so that boy can worry about removing obsolete points
// also maybe filter 180 degree angles before even doing this.
// i dont have a proof but im pretty sure this returns 1 if a polygon is clockwise and -1 if its counterclockwise for any concave or convex polygon. probably doesnt work if its self intersecting
let totalAngle = 0;
for(let i=0; i<polygon.length; i++){
let v0 = createVector( polygon[i][0] - polygon[(polygon.length+i-1)%polygon.length][0],
polygon[i][1] - polygon[(polygon.length+i-1)%polygon.length][1]);
let v1 = createVector( polygon[i][0] - polygon[(i+1)%polygon.length][0],
polygon[i][1] - polygon[(i+1)%polygon.length][1]);
totalAngle += v1.angleBetween(v0);
}
return Math.sign(totalAngle);
}
function getOffsetPath(polygon, offset, clockDir){
let offsetPath = [];
for(let i=0; i<polygon.length; i++){
// vector going to previous point
let v0 = createVector( polygon[i][0] - polygon[(polygon.length+i-1)%polygon.length][0],
polygon[i][1] - polygon[(polygon.length+i-1)%polygon.length][1]);
// vector to next point
let v1 = createVector( polygon[i][0] - polygon[(i+1)%polygon.length][0],
polygon[i][1] - polygon[(i+1)%polygon.length][1]);
//get the direction
let vDir = p5.Vector.add(v0.setMag(1), v1.setMag(1));
// should it be flipped or no? if its clockwise it should go "to the right", if its counterclockwise it should go "to the left"
if(Math.sign( v1.angleBetween(v0) ) == clockDir){
vDir.mult(-1);
}
vDir.setMag(offset)
offsetPath.push([polygon[i][0] + vDir.x, polygon[i][1] + vDir.y])
}
return offsetPath;
}