xxxxxxxxxx
383
let pointArray = [];
let pointArrayCopy = [];
let pointArray3 = [];
let WhichPointMove = -1;
let WhichPointErase = -1;
let WhichPointWeight = -1;
let threshold = 5;
let DIV;
let Shape;
let checkboxCtrlPoints;
let checkboxCtrlPolygon;
let checkboxCtrlPointsLabel;
let checkboxMinMaxBox;
let checkboxCubicBspline;
let ShapeSlider;
let ShapeSlider1;
let ShapeSlider2;
let resolutionSlider;
let knots = [];
let n = pointArray.length-1;
function setup() {
createCanvas(800, 500);
setupGUI();
}
function draw() {
background(0);
if (checkboxCtrlPointsLabel.checked())
drawControlCtrlPointsLabel();
if (checkboxCtrlPolygon.checked())
drawControlPolygon();
if (checkboxCtrlPoints.checked())
drawControlPoints();
if (checkboxMinMaxBox.checked())
drawMinMaxBox();
if (checkboxCubicBSpline.checked()){
draw_BSpline_1();
draw_BSpline_2();
}
}
function CubicBSpline_1(t, lambda) {
let vectorx = math.matrix();
let vectory = math.matrix();
let n = pointArray.length - 1;
let N = math.matrix();
let p = new Point2D(0,0);
knots = knot_vector(n);
push();
textSize(11);
strokeWeight(4);
stroke(0);
fill('white');
if (checkboxCubicBSpline.checked())
text('Knot Vector: '+math.round(knots,2),5,height-5);
pop();
if (n == 2) {
let t_m = math.matrix([1, t, pow(t, 2), pow(t, 3)]);
let M = math.matrix([[1, 0, 0], [lambda - 2, 2 - lambda, 0], [1 - (2 * lambda), (3 * lambda) - 2, 1 - lambda], [lambda, -2 * lambda, lambda]]);
vectorx = math.matrix([[pointArray[0].x], [pointArray[1].x], [pointArray[2].x]]);
vectory = math.matrix([[pointArray[0].y], [pointArray[1].y], [pointArray[2].y]]);
N = math.multiply(t_m, M);
p.x = math.multiply(N, vectorx);
p.y = math.multiply(N, vectory);
}
return p;
}
function draw_BSpline_1()
{
DIV = resolutionSlider.value();
Shape = ShapeSlider.value();
let n = pointArray.length-1;
noFill();
stroke(255,0,0); // Change the color to red
strokeWeight(3); // Make the points 2 pixels in size
beginShape();
if (pointArray.length == 3)
{
for (let i = 0; i <= DIV; i += 1)
{
t = i / DIV;
lambda = Shape / 100;
let tempPoint = CubicBSpline_1(t, lambda);
vertex(tempPoint.x._data[0], tempPoint.y._data[0]);
}
}
endShape();
}
function CubicBSpline_2_1(t, lambda) {
DIV = resolutionSlider.value();
let vectorx = math.matrix();
let vectory = math.matrix();
let n = pointArray.length - 1;
let p1 = new Point2D(0,0);
let N = math.matrix();
knots = knot_vector(n);
push();
textSize(11);
strokeWeight(4);
stroke(0);
fill('white');
if (checkboxCubicBSpline.checked())
text('Knot Vector: '+math.round(knots,2),5,height-5);
pop();
if (n > 2) {
let t_m = math.matrix([1, t, pow(t, 2), pow(t, 3)]);
let M1 = math.matrix([[1, 0, 0], [lambda - 2, 2 - lambda, 0], [1 - (2 * lambda), ((5/2) * lambda) - (3/2), (1/2) * (1 - lambda)], [lambda, (-5/4) * lambda, (1/4) * lambda]]);
vectorx = math.matrix([[pointArray[0].x], [pointArray[1].x], [pointArray[2].x]]);
vectory = math.matrix([[pointArray[0].y], [pointArray[1].y], [pointArray[2].y]]);
N = math.multiply(t_m, M1);
p1.x = math.multiply(N, vectorx);
p1.y = math.multiply(N, vectory);
}
return p1;
}
function CubicBSpline_2_middle(t, lambda) {
DIV = resolutionSlider.value();
let vectorx = math.matrix();
let vectory = math.matrix();
let n = pointArray.length - 1;
let pi = new Point2D(0,0);
let N = math.matrix();
let A = [];
knots = knot_vector(n);
push();
textSize(11);
strokeWeight(4);
stroke(0);
fill('white');
if (checkboxCubicBSpline.checked())
text('Knot Vector: '+math.round(knots,2),5,height-5);
pop();
if (n > 3) {
for (let i = 3; i <= n-1; i++) {
let t_m = math.matrix([1, t, pow(t, 2), pow(t, 3)]);
let Mi = math.matrix([[(1/4) * (2 + lambda), (1/4) * (2 - lambda), 0], [(-1/4) * (4 + lambda), (1/4) * (4 + lambda), 0], [(1/4) * (2 - lambda), (1/4) * (-4 + (3 * lambda)), (1/2) * (1 - lambda)], [(1/4) * lambda, (-1/2) * lambda, (1/4) * lambda]]);
vectorx = math.matrix([[pointArray[i-2].x], [pointArray[i-1].x], [pointArray[i].x]]);
vectory = math.matrix([[pointArray[i-2].y], [pointArray[i-1].y], [pointArray[i].y]]);
N = math.multiply(t_m, Mi);
pi.x = math.multiply(N, vectorx);
pi.y = math.multiply(N, vectory);
//print('pi');
//print(pi);
A[i-3] = [pi.x._data[0],pi.y._data[0]];
}
}
//print('A');
//print(A);
return A;
}
function CubicBSpline_2_end(t, lambda) {
DIV = resolutionSlider.value();
let vectorx = math.matrix();
let vectory = math.matrix();
let n = pointArray.length - 1;
let pn = new Point2D(0,0);
let N = math.matrix();
knots = knot_vector(n);
push();
textSize(11);
strokeWeight(4);
stroke(0);
fill('white');
if (checkboxCubicBSpline.checked())
text('Knot Vector: '+math.round(knots,2),5,height-5);
pop();
if (n > 2) {
let t_m = math.matrix([1, t, pow(t, 2), pow(t, 3)]);
let Mn = math.matrix([[(1/2) + ((1/4) * lambda), (1/4) * (2 - lambda), 0], [-1 - ((1/4) * lambda), 1 + ((1/4) * lambda), 0], [(1/2) - ((1/4) * lambda), ((5/4) * lambda) - (3/2), 1 - lambda], [(1/4) * lambda, (-5/4) * lambda, lambda]]);
vectorx = math.matrix([[pointArray[n-2].x], [pointArray[n-1].x], [pointArray[n].x]]);
vectory = math.matrix([[pointArray[n-2].y], [pointArray[n-1].y], [pointArray[n].y]]);
N = math.multiply(t_m, Mn);
pn.x = math.multiply(N, vectorx);
pn.y = math.multiply(N, vectory);
}
return pn;
}
function draw_BSpline_2(){
DIV = resolutionSlider.value();
Shape = ShapeSlider.value();
let n = pointArray.length - 1;
noFill();
stroke(255,0,0); // Change the color to red
strokeWeight(3); // Make the points 2 pixels in size
beginShape();
for (let i = 0; i <= DIV; i += 1) {
t = i / DIV;
lambda = Shape / 100;
if (pointArray.length > 3) {
let tempPoint_1 = CubicBSpline_2_1(t, lambda);
vertex(tempPoint_1.x._data[0],tempPoint_1.y._data[0]);
}
}
for (let k = 3; k <= n-1; k++){
for (let i = 0; i <= DIV; i += 1){
t = i / DIV;
lambda = Shape / 100;
if (pointArray.length > 4){
let tempPoint_i = CubicBSpline_2_middle(t, lambda);
//print(tempPoint_i.x._data[0],tempPoint_i.y._data[0]);
vertex(tempPoint_i[k-3][0], tempPoint_i[k-3][1]);
}
}
}
for (let i = 0; i <= DIV; i += 1){
t = i / DIV;
lambda = Shape / 100;
if (pointArray.length > 3){
let tempPoint_n = CubicBSpline_2_end(t, lambda);
//print(tempPoint_n);
vertex(tempPoint_n.x._data[0],tempPoint_n.y._data[0]);
}
}
endShape();
}
function knot_vector(n) {
m = n+3; //Since p = 2 always, we hard coded that into the knot vector code.
U = [];
for (let i = 0; i <= m ; i++)
U[i] = 0;
j = 1;
for (let i = 3; i <= m-2 ; i++) {
segment = m-4;
U[i] = j/segment;
j++;
}
for (let i = m-2; i <= m ; i++)
U[i] = 1;
return U;
}
function drawControlPoints()
{
stroke(255,0,255,200); // Change the color
strokeWeight(10); // Make the points 10 pixels in size
for (let i=0; i< pointArray.length; i++)
point(pointArray[i].x, pointArray[i].y);
}
function drawControlCtrlPointsLabel()
{
stroke(200);
textSize(15);
strokeWeight(1);
noFill();
for (let i=0; i< pointArray.length; i++)
text(i, pointArray[i].x, pointArray[i].y-10);
}
function drawControlPolygon()
{
noFill();
stroke('white');
strokeWeight(2);
beginShape();
for (let i=0; i< pointArray.length; i++)
vertex(pointArray[i].x, pointArray[i].y);
endShape();
}
function drawMinMaxBox()
{
if (pointArray.length > 0)
{
let x_max, x_min, y_max, y_min;
x_max = pointArray[0].x;
x_min = pointArray[0].x;
y_max = pointArray[0].y;
y_min = pointArray[0].y;
for (let i = 0; i < pointArray.length; i++) {
if (pointArray[i].x > x_max)
x_max = pointArray[i].x;
else if (pointArray[i].x < x_min)
x_min = pointArray[i].x;
if (pointArray[i].y > y_max)
y_max = pointArray[i].y;
else if (pointArray[i].y < y_min)
y_min = pointArray[i].y;
}
noFill();
stroke(220);
strokeWeight(1);
beginShape();
vertex(x_max, y_max);
vertex(x_min, y_max);
vertex(x_min, y_min);
vertex(x_max, y_min);
endShape(CLOSE);
}
}
function setupGUI()
{
resetButton = createButton('Clear Canvas');
resetButton.mousePressed(reset); // call reset function when pressed
checkboxCtrlPoints = createCheckbox('Show Control Points', true);
checkboxCtrlPolygon = createCheckbox('Show Control Polygon', true);
checkboxCtrlPointsLabel = createCheckbox('Show Control Point Labels', true);
checkboxMinMaxBox = createCheckbox('Show Min-Max Box', true);
checkboxCubicBSpline = createCheckbox('Show Cubic B-Spline', true);
var resP = createP('Curve Resolution:');
resolutionSlider = createSlider(10,200,30); // args are min, max, and default
resolutionSlider.parent(resP); //make slider a child of resP to align next to each other
var lambda = createP('Lambda :')
ShapeSlider = createSlider(-100, 100, 0);
ShapeSlider.parent(lambda);
createP('Generate a curve by creating control points on the canvas (at least 3). Use the lambda slider to adjust curve within range.')
createP('Left click adds a new point.');
createP('Right click and drag moves an existing point.');
createP('Middle click removes an existing point');
}
function reset()
{
pointArray = [];
WhichPointMove = -1;
ShapeSlider.value(1);
resolutionSlider.value(30);
}