沿垂直方向的反射矢量

发布于 2025-01-10 04:28:56 字数 10629 浏览 0 评论 0原文

在 SO 社区的大力帮助下,我创建了一个程序,其中一个球处于具有特定位置和速度的三角形中。使用参数方程,我确定了球将击中三角形的位置。然后,我找到了球将击中的三角形边的垂直线,这样我就可以将球反射到墙上,以绘制其“弹跳”轨迹。我的目标是能够绘制出 n 次迭代中球如何从墙壁上弹起的图。但我遇到了一个问题。

尽管我使用 p5.js A.reflect(B) 方法沿垂直方向反射球,但它会产生一些真正奇怪的结果。 输入图片此处描述我尝试了很多事情(即修改getPerp()函数、单元测试等),但没有成功。任何帮助将不胜感激。 MWE 下面和 Codepen 中。

let angle = 0;
let sides = [];
let vertices = [];
const len = 100;

function setup() {
    createCanvas(windowWidth, windowHeight);
    angleMode(DEGREES);

    angleOne = createSlider(0, 89, 60);
    angleOne.position(10, 10);
    angleOne.style("width", "80px");

    angleTwo = createSlider(0, 89, 60);
    angleTwo.position(10, 30);
    angleTwo.style("width", "80px");

    rotateVel = createSlider(0, 360, 60);
    rotateVel.position(10, 50);
    rotateVel.style("width", "80px");

    // Initial vertice & side setup (these don't change)
    let v1 = createVector(width / 2 - len / 2, height / 2);
    let v2 = createVector(width / 2 + len / 2, height / 2);

    sides[0] = new Side(v1.x, v1.y, v2.x, v2.y, "green");

    vertices[0] = new Vertex(v1.x, v1.y);
    vertices[1] = new Vertex(v2.x, v2.y);
}

function draw() {
    background(255);

    let angOne = angleOne.value();
    let angTwo = angleTwo.value();
    let rotVel = rotateVel.value();
    fill(0);
    strokeWeight(0);
    textSize(15);
    text(angOne, 100, 25);
    text(angTwo, 100, 45);
    text(rotVel, 100, 65);

    let v2Offset = createVector(len * cos(-angOne), len * sin(-angOne));
    let v3Offset = createVector(-len * cos(angTwo), -len * sin(angTwo));

    vertices[2] = new Vertex(
        vertices[0].a.x + v2Offset.x,
        vertices[0].a.y + v2Offset.y
    );
    vertices[3] = new Vertex(
        vertices[1].a.x + v3Offset.x,
        vertices[1].a.y + v3Offset.y
    );

    // Update the sides
    sides[1] = new Side(
        vertices[0].a.x,
        vertices[0].a.y,
        vertices[2].a.x,
        vertices[2].a.y
    );

    sides[3] = new Side(
        vertices[1].a.x,
        vertices[1].a.y,
        vertices[3].a.x,
        vertices[3].a.y
    );

    const m1 =
        (vertices[2].a.y - vertices[0].a.y) / (vertices[2].a.x - vertices[0].a.x);

    const m2 =
        (vertices[3].a.y - vertices[1].a.y) / (vertices[3].a.x - vertices[1].a.x);

    // Calculate the y-offset relative to vertices[0]
    const b2 = (vertices[1].a.x - vertices[0].a.x) * -m2;

    const xInt = b2 / (m1 - m2);
    const yInt = xInt * m1;
    // Note xInt and yInt are relative to vertices[0]

    // draw all the things
    // sides.forEach((s) => s.show());

    // stroke(0, 255, 0);
    // strokeWeight(20);
    point(vertices[0].a.x + xInt, vertices[0].a.y + yInt);

    vertices[4] = new Vertex(vertices[0].a.x + xInt, vertices[0].a.y + yInt);

    sides[4] = new Side(
        vertices[1].a.x,
        vertices[1].a.y,
        vertices[0].a.x + xInt,
        vertices[0].a.y + yInt,
        "blue"
    );

    sides[5] = new Side(
        vertices[0].a.x,
        vertices[0].a.y,
        vertices[0].a.x + xInt,
        vertices[0].a.y + yInt,
        "purple"
    );

    scale(4); // so I can make the triangle actually *visible*
    translate(-width / 3, -height / 3);

    sides[0].show();
    sides[4].show();
    sides[5].show();

    vertices[0].show();
    vertices[1].show();
    vertices[4].show();

    strokeWeight(1);
    stroke(255, 0, 0);
    noFill();
    arc(vertices[0].a.x, vertices[0].a.y, 40, 40, -1 * angleOne.value(), 0, PIE);
    arc(
        vertices[1].a.x,
        vertices[1].a.y,
        40,
        40,
        -180,
        -(180 - angleTwo.value()),
        PIE
    );

    stroke(0);
    // stroke("purple"); // Change the color
    strokeWeight(5); // Make the points 10 pixels in size

    let P1x = vertices[0].a.x;
    let P1y = vertices[0].a.y;

    let P0 = createVector(P1x + 60, P1y - 40);

    push();
    let V0 = createVector(10 * cos(rotVel), 10 * sin(-rotVel));
    pop();

    point(P0.x, P0.y);

    // point(P0.x + V0.x, P0.y + V0.y);
    strokeWeight(2);
    line(P0.x, P0.y, P0.x + V0.x, P0.y + V0.y);

    let hit = wallHit(P0, V0);
    // print("hit[0] is", hit[0]);
    hitPoint = createVector(P0.x + V0.x * hit[0], P0.y + V0.y * hit[0]);

    let A = createVector(
        vertices[4].a.x - vertices[1].a.x,
        vertices[4].a.y - vertices[1].a.y
    );
    // let B = p5.Vector.sub(vertices[1].a, vertices[2].a);
    // let C = p5.Vector.sub(vertices[2].a, vertices[4].a);
    // findNormal(hitPoint, A);
    setLineDash([5, 5]);
    stroke(0);

    // let perpA = getY(vertices[1].a.x - 100, hitPoint);
    // let normalA = createVector(vertices[1].a.x - 100, perpA);
    // let incVec = createVector(hitPoint.x, hitPoint.y);
    // let refVec = normalA.reflect(incVec);
    let IOne = createVector(0, 0);
    let ITwo = createVector(0, 0);
    let IThree = createVector(0, 0);

    // line(hitPoint.x, hitPoint.y, normalA.x, normalA.y);
    let AOne = createVector(P1x, P1y);
    let ATwo = createVector(vertices[1].a.x, vertices[1].a.y + 0.1);
    let AThree = createVector(
        (P1x + vertices[1].a.x) / 2,
        (P1y + vertices[1].a.y) / 2
    );
    // getPerp(AOne, ATwo, hitPoint);

    let BOne = createVector(P1x, P1y);
    let BTwo = createVector(vertices[4].a.x, vertices[4].a.y + 0.1);
    let BThree = createVector(
        (P1x + vertices[4].a.x) / 2,
        (P1y + vertices[4].a.y) / 2
    );
    // getPerp(BOne, BTwo, hitPoint);

    let COne = createVector(vertices[1].a.x, vertices[1].a.y);
    let CTwo = createVector(vertices[4].a.x, vertices[4].a.y + 0.1);
    let CThree = createVector(
        (vertices[1].a.x + vertices[4].a.x) / 2,
        (vertices[1].a.y + vertices[4].a.y) / 2
    );
    // getPerp(COne, CTwo, hitPoint);
    let incVec = createVector(hitPoint.x, hitPoint.y);
    line(P0.x, P0.y, incVec.x, incVec.y);
    let perp = getPerp(IOne, ITwo, IThree);

    let testOne = createVector(vertices[0].a.x + 20, vertices[0].a.y + 20);
    let testTwo = createVector(vertices[1].a.x + 20, vertices[1].a.y + 20);
    let refVec = testOne.reflect(testTwo);
    // line(testOne.x, testOne.y, testTwo.x, testTwo.y);

    if (hit[1] == "t3") {
        perp = getPerp(AOne, ATwo, hitPoint);
        refVec = perp.reflect(incVec);
    } else if (hit[1] == "t1") {
        perp = getPerp(BOne, BTwo, hitPoint);
        refVec = perp.reflect(incVec);
    } else {
        perp = getPerp(COne, CTwo, hitPoint);
        refVec = perp.reflect(incVec);
    }
    stroke("black");
    line(hitPoint.x, hitPoint.y, refVec.x, refVec.y);

    setLineDash([0, 0]);
}

function setLineDash(list) {
    drawingContext.setLineDash(list);
}

class Side {
    constructor(x1, y1, x2, y2, col = "black") {
        this.a = createVector(x1, y1);
        this.b = createVector(x2, y2);
        this.color = col;
    }

    show() {
        stroke(this.color);
        strokeWeight(4);
        line(this.a.x, this.a.y, this.b.x, this.b.y);
    }
}

class Vertex {
    constructor(x1, y1) {
        this.a = createVector(x1, y1);
    }

    show() {
        stroke(255, 0, 0);
        strokeWeight(10);
        point(this.a.x, this.a.y);
    }
}

function wallHit(pos, vel) {
    let P1x = vertices[0].a.x;
    let P1y = vertices[0].a.y;

    let P2x = vertices[1].a.x;
    let P2y = vertices[1].a.y;

    let P3x = vertices[4].a.x;
    let P3y = vertices[4].a.y;

    let A1 = P3y - P1y;
    let B1 = -(P3x - P1x);
    let C1 = A1 * P1x + B1 * P1y;

    let A2 = -(P3y - P2y);
    let B2 = P3x - P2x;
    let C2 = A2 * P2x + B2 * P2y;

    let A3 = -(P2y - P1y);
    let B3 = P2x - P1x;
    let C3 = A3 * P2x + B3 * P2y;

    let t1 = (C1 - A1 * pos.x - B1 * pos.y) / (A1 * vel.x + B1 * vel.y);
    let t2 = (C2 - A2 * pos.x - B2 * pos.y) / (A2 * vel.x + B2 * vel.y);
    let t3 = (C3 - A3 * pos.x - B3 * pos.y) / (A3 * vel.x + B3 * vel.y);

    let times = [t1, t2, t3];
    let posTimes = [];

    for (let i = 0; i < times.length; i++) {
        times[i] = round(times[i], 2);
    }

    // console.log("After rounding:", times);

    for (let i = 0; i < times.length; i++) {
        if (times[i] > 0) {
            posTimes.push(times[i]);
        }
    }

    let hitPoint = createVector(0, 1);
    // console.log("posTimes:", posTimes);
    trueTime = min(posTimes);

    if (trueTime == round(t1, 2)) {
        // print("Hit Purple");
        return [t1, "t1"];
        // hitPoint = createVector(P0.x + V0.x * t1, P0.y + V0.y * t1);
        // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
    } else if (trueTime == round(t2, 2)) {
        // print("Hit Blue");
        return [t2, "t2"];
        // hitPoint = createVector(P0.x + V0.x * t2, P0.y + V0.y * t2);
        // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
    } else {
        // print("Hit Green");
        return [t3, "t3"];
        // hitPoint = createVector(P0.x + V0.x * t3, P0.y + V0.y * t3);
        // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
    }
}

function findNormal(pos, wall) {
    let perpVector = createVector(-wall.y, wall.x);
    strokeWeight(2);
    stroke(0);
    line(pos.x, pos.y, perpVector.x, perpVector.y);
    // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
}

function getY(x, HP) {
    let perpY =
        -((vertices[4].a.x - vertices[1].a.x) / (vertices[4].a.y - vertices[1].a.y)) *
            x +
        (HP.y +
            ((vertices[4].a.x - vertices[1].a.x) / (vertices[4].a.y - vertices[1].a.y)) *
                HP.x);
    return perpY;
}

function getPerp(p1, p2, p3) {
    x1 = p1.x;
    y1 = p1.y;
    x2 = p2.x;
    y2 = p2.y;
    x3 = p3.x;
    y3 = p3.y;
    stroke(0);
    strokeWeight(2);
    line1 = line(x1, y1, x2, y2);
    m1 = (y2 - y1) / (x2 - x1);
    m2 = -1 / m1;
    b2 = y3 - x3 * m2;
    stroke(255, 0, 0);
    line(x3, m2 * x3 + b2, x1, m2 * x1 + b2);
    let final = createVector(m2 * x1 + b2 - (m2 * x3 + b2), x1 - x3);
    return final;
}
html,
body {
    margin: 0;
    padding: 0;
    overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.min.js"></script>

With much help from the SO community, I've created a program where a ball is in a triangle with a certain position and velocity. Using parametric equations, I've determined where the ball will hit the triangle. I then found the perpendicular to the side of the triangle where the ball would hit, so that I could reflect the ball off the wall, to plot its "bounce" trajectory. My goal is that I can plot how the ball will bounce off the walls for n iterations. But I've come up against a problem.

Even though I'm using the p5.js A.reflect(B) method to reflect the ball along the perpendicular, it's producing some truly strange results.
enter image description here
I've tried many things (i.e., modifying the getPerp() function, unit testing, etc.), but to no avail. Any help would be greatly appreciated. MWE below and in Codepen.

let angle = 0;
let sides = [];
let vertices = [];
const len = 100;

function setup() {
    createCanvas(windowWidth, windowHeight);
    angleMode(DEGREES);

    angleOne = createSlider(0, 89, 60);
    angleOne.position(10, 10);
    angleOne.style("width", "80px");

    angleTwo = createSlider(0, 89, 60);
    angleTwo.position(10, 30);
    angleTwo.style("width", "80px");

    rotateVel = createSlider(0, 360, 60);
    rotateVel.position(10, 50);
    rotateVel.style("width", "80px");

    // Initial vertice & side setup (these don't change)
    let v1 = createVector(width / 2 - len / 2, height / 2);
    let v2 = createVector(width / 2 + len / 2, height / 2);

    sides[0] = new Side(v1.x, v1.y, v2.x, v2.y, "green");

    vertices[0] = new Vertex(v1.x, v1.y);
    vertices[1] = new Vertex(v2.x, v2.y);
}

function draw() {
    background(255);

    let angOne = angleOne.value();
    let angTwo = angleTwo.value();
    let rotVel = rotateVel.value();
    fill(0);
    strokeWeight(0);
    textSize(15);
    text(angOne, 100, 25);
    text(angTwo, 100, 45);
    text(rotVel, 100, 65);

    let v2Offset = createVector(len * cos(-angOne), len * sin(-angOne));
    let v3Offset = createVector(-len * cos(angTwo), -len * sin(angTwo));

    vertices[2] = new Vertex(
        vertices[0].a.x + v2Offset.x,
        vertices[0].a.y + v2Offset.y
    );
    vertices[3] = new Vertex(
        vertices[1].a.x + v3Offset.x,
        vertices[1].a.y + v3Offset.y
    );

    // Update the sides
    sides[1] = new Side(
        vertices[0].a.x,
        vertices[0].a.y,
        vertices[2].a.x,
        vertices[2].a.y
    );

    sides[3] = new Side(
        vertices[1].a.x,
        vertices[1].a.y,
        vertices[3].a.x,
        vertices[3].a.y
    );

    const m1 =
        (vertices[2].a.y - vertices[0].a.y) / (vertices[2].a.x - vertices[0].a.x);

    const m2 =
        (vertices[3].a.y - vertices[1].a.y) / (vertices[3].a.x - vertices[1].a.x);

    // Calculate the y-offset relative to vertices[0]
    const b2 = (vertices[1].a.x - vertices[0].a.x) * -m2;

    const xInt = b2 / (m1 - m2);
    const yInt = xInt * m1;
    // Note xInt and yInt are relative to vertices[0]

    // draw all the things
    // sides.forEach((s) => s.show());

    // stroke(0, 255, 0);
    // strokeWeight(20);
    point(vertices[0].a.x + xInt, vertices[0].a.y + yInt);

    vertices[4] = new Vertex(vertices[0].a.x + xInt, vertices[0].a.y + yInt);

    sides[4] = new Side(
        vertices[1].a.x,
        vertices[1].a.y,
        vertices[0].a.x + xInt,
        vertices[0].a.y + yInt,
        "blue"
    );

    sides[5] = new Side(
        vertices[0].a.x,
        vertices[0].a.y,
        vertices[0].a.x + xInt,
        vertices[0].a.y + yInt,
        "purple"
    );

    scale(4); // so I can make the triangle actually *visible*
    translate(-width / 3, -height / 3);

    sides[0].show();
    sides[4].show();
    sides[5].show();

    vertices[0].show();
    vertices[1].show();
    vertices[4].show();

    strokeWeight(1);
    stroke(255, 0, 0);
    noFill();
    arc(vertices[0].a.x, vertices[0].a.y, 40, 40, -1 * angleOne.value(), 0, PIE);
    arc(
        vertices[1].a.x,
        vertices[1].a.y,
        40,
        40,
        -180,
        -(180 - angleTwo.value()),
        PIE
    );

    stroke(0);
    // stroke("purple"); // Change the color
    strokeWeight(5); // Make the points 10 pixels in size

    let P1x = vertices[0].a.x;
    let P1y = vertices[0].a.y;

    let P0 = createVector(P1x + 60, P1y - 40);

    push();
    let V0 = createVector(10 * cos(rotVel), 10 * sin(-rotVel));
    pop();

    point(P0.x, P0.y);

    // point(P0.x + V0.x, P0.y + V0.y);
    strokeWeight(2);
    line(P0.x, P0.y, P0.x + V0.x, P0.y + V0.y);

    let hit = wallHit(P0, V0);
    // print("hit[0] is", hit[0]);
    hitPoint = createVector(P0.x + V0.x * hit[0], P0.y + V0.y * hit[0]);

    let A = createVector(
        vertices[4].a.x - vertices[1].a.x,
        vertices[4].a.y - vertices[1].a.y
    );
    // let B = p5.Vector.sub(vertices[1].a, vertices[2].a);
    // let C = p5.Vector.sub(vertices[2].a, vertices[4].a);
    // findNormal(hitPoint, A);
    setLineDash([5, 5]);
    stroke(0);

    // let perpA = getY(vertices[1].a.x - 100, hitPoint);
    // let normalA = createVector(vertices[1].a.x - 100, perpA);
    // let incVec = createVector(hitPoint.x, hitPoint.y);
    // let refVec = normalA.reflect(incVec);
    let IOne = createVector(0, 0);
    let ITwo = createVector(0, 0);
    let IThree = createVector(0, 0);

    // line(hitPoint.x, hitPoint.y, normalA.x, normalA.y);
    let AOne = createVector(P1x, P1y);
    let ATwo = createVector(vertices[1].a.x, vertices[1].a.y + 0.1);
    let AThree = createVector(
        (P1x + vertices[1].a.x) / 2,
        (P1y + vertices[1].a.y) / 2
    );
    // getPerp(AOne, ATwo, hitPoint);

    let BOne = createVector(P1x, P1y);
    let BTwo = createVector(vertices[4].a.x, vertices[4].a.y + 0.1);
    let BThree = createVector(
        (P1x + vertices[4].a.x) / 2,
        (P1y + vertices[4].a.y) / 2
    );
    // getPerp(BOne, BTwo, hitPoint);

    let COne = createVector(vertices[1].a.x, vertices[1].a.y);
    let CTwo = createVector(vertices[4].a.x, vertices[4].a.y + 0.1);
    let CThree = createVector(
        (vertices[1].a.x + vertices[4].a.x) / 2,
        (vertices[1].a.y + vertices[4].a.y) / 2
    );
    // getPerp(COne, CTwo, hitPoint);
    let incVec = createVector(hitPoint.x, hitPoint.y);
    line(P0.x, P0.y, incVec.x, incVec.y);
    let perp = getPerp(IOne, ITwo, IThree);

    let testOne = createVector(vertices[0].a.x + 20, vertices[0].a.y + 20);
    let testTwo = createVector(vertices[1].a.x + 20, vertices[1].a.y + 20);
    let refVec = testOne.reflect(testTwo);
    // line(testOne.x, testOne.y, testTwo.x, testTwo.y);

    if (hit[1] == "t3") {
        perp = getPerp(AOne, ATwo, hitPoint);
        refVec = perp.reflect(incVec);
    } else if (hit[1] == "t1") {
        perp = getPerp(BOne, BTwo, hitPoint);
        refVec = perp.reflect(incVec);
    } else {
        perp = getPerp(COne, CTwo, hitPoint);
        refVec = perp.reflect(incVec);
    }
    stroke("black");
    line(hitPoint.x, hitPoint.y, refVec.x, refVec.y);

    setLineDash([0, 0]);
}

function setLineDash(list) {
    drawingContext.setLineDash(list);
}

class Side {
    constructor(x1, y1, x2, y2, col = "black") {
        this.a = createVector(x1, y1);
        this.b = createVector(x2, y2);
        this.color = col;
    }

    show() {
        stroke(this.color);
        strokeWeight(4);
        line(this.a.x, this.a.y, this.b.x, this.b.y);
    }
}

class Vertex {
    constructor(x1, y1) {
        this.a = createVector(x1, y1);
    }

    show() {
        stroke(255, 0, 0);
        strokeWeight(10);
        point(this.a.x, this.a.y);
    }
}

function wallHit(pos, vel) {
    let P1x = vertices[0].a.x;
    let P1y = vertices[0].a.y;

    let P2x = vertices[1].a.x;
    let P2y = vertices[1].a.y;

    let P3x = vertices[4].a.x;
    let P3y = vertices[4].a.y;

    let A1 = P3y - P1y;
    let B1 = -(P3x - P1x);
    let C1 = A1 * P1x + B1 * P1y;

    let A2 = -(P3y - P2y);
    let B2 = P3x - P2x;
    let C2 = A2 * P2x + B2 * P2y;

    let A3 = -(P2y - P1y);
    let B3 = P2x - P1x;
    let C3 = A3 * P2x + B3 * P2y;

    let t1 = (C1 - A1 * pos.x - B1 * pos.y) / (A1 * vel.x + B1 * vel.y);
    let t2 = (C2 - A2 * pos.x - B2 * pos.y) / (A2 * vel.x + B2 * vel.y);
    let t3 = (C3 - A3 * pos.x - B3 * pos.y) / (A3 * vel.x + B3 * vel.y);

    let times = [t1, t2, t3];
    let posTimes = [];

    for (let i = 0; i < times.length; i++) {
        times[i] = round(times[i], 2);
    }

    // console.log("After rounding:", times);

    for (let i = 0; i < times.length; i++) {
        if (times[i] > 0) {
            posTimes.push(times[i]);
        }
    }

    let hitPoint = createVector(0, 1);
    // console.log("posTimes:", posTimes);
    trueTime = min(posTimes);

    if (trueTime == round(t1, 2)) {
        // print("Hit Purple");
        return [t1, "t1"];
        // hitPoint = createVector(P0.x + V0.x * t1, P0.y + V0.y * t1);
        // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
    } else if (trueTime == round(t2, 2)) {
        // print("Hit Blue");
        return [t2, "t2"];
        // hitPoint = createVector(P0.x + V0.x * t2, P0.y + V0.y * t2);
        // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
    } else {
        // print("Hit Green");
        return [t3, "t3"];
        // hitPoint = createVector(P0.x + V0.x * t3, P0.y + V0.y * t3);
        // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
    }
}

function findNormal(pos, wall) {
    let perpVector = createVector(-wall.y, wall.x);
    strokeWeight(2);
    stroke(0);
    line(pos.x, pos.y, perpVector.x, perpVector.y);
    // line(P0.x, P0.y, hitPoint.x, hitPoint.y);
}

function getY(x, HP) {
    let perpY =
        -((vertices[4].a.x - vertices[1].a.x) / (vertices[4].a.y - vertices[1].a.y)) *
            x +
        (HP.y +
            ((vertices[4].a.x - vertices[1].a.x) / (vertices[4].a.y - vertices[1].a.y)) *
                HP.x);
    return perpY;
}

function getPerp(p1, p2, p3) {
    x1 = p1.x;
    y1 = p1.y;
    x2 = p2.x;
    y2 = p2.y;
    x3 = p3.x;
    y3 = p3.y;
    stroke(0);
    strokeWeight(2);
    line1 = line(x1, y1, x2, y2);
    m1 = (y2 - y1) / (x2 - x1);
    m2 = -1 / m1;
    b2 = y3 - x3 * m2;
    stroke(255, 0, 0);
    line(x3, m2 * x3 + b2, x1, m2 * x1 + b2);
    let final = createVector(m2 * x1 + b2 - (m2 * x3 + b2), x1 - x3);
    return final;
}
html,
body {
    margin: 0;
    padding: 0;
    overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.min.js"></script>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤蝉 2025-01-17 04:28:56

您混淆了向量和点。一个点有 2 个从坐标系原点测量的坐标。向量表示方向,可以通过减去 2 个点来给出。因此,入射向量为:

inVec = createVector(hitPoint.x - P0.x, hitPoint.y - P0.y);

向量 (Vx, Vy) 的法向量(垂直向量)为:

N = (-Vy, Vx)

因此,由 2 个点 (Ax, Ay) 和 (Bx, By) 给出的直线的法向量(垂直)为:

N = (Ay - By, Bx - Ax)

reflect() 函数反映了表面上的入射矢量除以表面的给定法线矢量。函数的参数是法向量:

refVec = inVec.reflect(n);

line 在两点之间画一条线。 refVec 不是一个点而是一个向量。因此,您需要绘制从 hitPointhitPoint + refVec 的直线,而不是从 hitPointrefVec 的形式。

全部在一起:

inVec = createVector(hitPoint.x - P0.x, hitPoint.y - P0.y);
if (hit[1] == "t3") {
    perp = getPerp(AOne, ATwo, hitPoint);
    let n = createVector(AOne.y - ATwo.y, ATwo.x - AOne.x);
    refVec = inVec.reflect(n);
} else if (hit[1] == "t1") {
    perp = getPerp(BOne, BTwo, hitPoint);
    let n = createVector(BOne.y - BTwo.y, BTwo.x - BOne.x);
    refVec = inVec.reflect(n);
} else {
    perp = getPerp(COne, CTwo, hitPoint);
    let n = createVector(COne.y - CTwo.y, CTwo.x - COne.x);
    refVec = inVec.reflect(n);
}
stroke("black");
line(hitPoint.x, hitPoint.y, hitPoint.x + refVec.x, hitPoint.y + refVec.y);

演示

You are confusing vectors and points. A point has 2 coordinates measured from the origin of the coordinate system. A vector represents a direction and can be given by subtracting 2 points. Therefore, the incident vector is:

inVec = createVector(hitPoint.x - P0.x, hitPoint.y - P0.y);

The normal vector (perpendicular vector) of a vector (Vx, Vy) is:

N = (-Vy, Vx)

Hence the normal vector (perpendicular) to a line given by 2 points (Ax, Ay) and (Bx, By) is:

N = (Ay - By, Bx - Ax)

The reflect() function reflects an incidence vector on a surface by a given normal vector of the surface. The argument of the function is the normal vector:

refVec = inVec.reflect(n);

line draws a line between 2 points. refVec is not a point but a vector. Therefore you need to draw the line from hitPoint to hitPoint + refVec instead of form hitPoint to refVec.

All together:

inVec = createVector(hitPoint.x - P0.x, hitPoint.y - P0.y);
if (hit[1] == "t3") {
    perp = getPerp(AOne, ATwo, hitPoint);
    let n = createVector(AOne.y - ATwo.y, ATwo.x - AOne.x);
    refVec = inVec.reflect(n);
} else if (hit[1] == "t1") {
    perp = getPerp(BOne, BTwo, hitPoint);
    let n = createVector(BOne.y - BTwo.y, BTwo.x - BOne.x);
    refVec = inVec.reflect(n);
} else {
    perp = getPerp(COne, CTwo, hitPoint);
    let n = createVector(COne.y - CTwo.y, CTwo.x - COne.x);
    refVec = inVec.reflect(n);
}
stroke("black");
line(hitPoint.x, hitPoint.y, hitPoint.x + refVec.x, hitPoint.y + refVec.y);

Demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文