簡體   English   中英

如何使用p5.js計算圓上線的交點

[英]How to calculate intersection point of a line on a circle using p5.js

我有一條直線( se ),我知道它在一個圓圈內開始,並且我知道在一個圓圈外結束。 我試圖找到直線與圓相交的點l

計算圓的直線相交點–設置

我正在使用p5.j​​s庫,並且可以訪問其所有Vector函數。

我的想法是,如果我可以使直線與半徑成直角,就可以開始解決一些問題。

計算圓中線的交點–嘗試

// Get the vector between s and c
let scVector = p5.Vector.sub(start, circleCenter);
// Get the angle between se and sc
let escAngle = this.v.angleBetween(scVector);
// Get the distance between t (where the right angle hits the center of the circle) and c
let tcDistance = Math.sin(escAngle) * scVector.mag();
// Get the distance between t and where the line intersects the circle
let tlDistance = Math.sqrt(Math.pow(hole.r, 2) - Math.pow(tcDistance, 2));
// Get the distance between the start point and t
let stDistance = Math.sqrt(Math.pow(scVector.mag(), 2) - Math.pow(tcDistance, 2));
// Add the two distances together, giving me the distance between s and l
let totalDistance = tcDistance + stDistance;
// Create a new Vector at this angle, at the totalDistance Magnitude, then add it to the current position
let point = p5.Vector.fromAngle(this.v.heading(), totalDistance).add(start);
// Mark a point (hopefully l) on the edge of the circle.
points.push({
  x: point.x,
  y: point.y,
  fill: '#ffffff'
})

不幸的是,當我的對象通過圓時,它們沒有在邊緣上留下點,而是遠離圓的邊緣。

在此處輸入圖片說明

小點是標記的位置,彩色點是對象(具有起點和終點)

我在這里有一個演示,可疑的地方是第42行及以后: https : //codepen.io/EightArmsHQ/pen/be0461014f9868e3462868776d9c8f1a

任何幫助將非常感激。

為了找到點與線的交點,我建議使用現有的算法,例如WolframMathWorld-Circle-Line Intersection之一

該算法簡短,可以用簡短函數表示。 輸入參數p1p2cpt的類型為p5.Vectorr是標量。 該參數定義了一條從p1p2的環形線以及一個以中心點cpt和半徑r為中心的圓。 該函數返回交叉點列表,可能為空:

intersectLineCircle = function(p1, p2, cpt, r) {

    let sign = function(x) { return x < 0.0 ? -1 : 1; };

    let x1 = p1.copy().sub(cpt);
    let x2 = p2.copy().sub(cpt);

    let dv = x2.copy().sub(x1)
    let dr = dv.mag();
    let D = x1.x*x2.y - x2.x*x1.y;

    // evaluate if there is an intersection
    let di = r*r*dr*dr - D*D;
    if (di < 0.0)
        return [];

    let t = sqrt(di);

    ip = [];
    ip.push( new p5.Vector(D*dv.y + sign(dv.y)*dv.x * t, -D*dv.x + p.abs(dv.y) * t).div(dr*dr).add(cpt) );
    if (di > 0.0) {
        ip.push( new p5.Vector(D*dv.y - sign(dv.y)*dv.x * t, -D*dv.x - p.abs(dv.y) * t).div(dr*dr).add(cpt) ); 
    }
    return ip;
}

如果要驗證,如果某個點位於其他點之間,則可以使用Dot產品 如果您知道一條線上有3個點,則足以計算這些點之間的距離,並確定在其他2個點之間是否有1個點。
p1p2px的類型為p5.Vector 這些點在同一條線上。 如果pxp1p2之間,則該函數返回true ,否則返回false

inBetween = function(p1, p2, px) {

    let v = p2.copy().sub(p1);
    let d = v.mag();
    v = v.normalize();

    let vx = px.copy().sub(p1);
    let dx = v.dot(vx);

    return dx >= 0 && dx <= d;
}

請參閱示例,該示例已經實現以測試該功能。 該圓由鼠標跟蹤,並與一條隨機移動的線相交:

 var sketch = function( p ) { p.setup = function() { let sketchCanvas = p.createCanvas(p.windowWidth, p.windowHeight); sketchCanvas.parent('p5js_canvas') } let points = []; let move = [] // Circle-Line Intersection // http://mathworld.wolfram.com/Circle-LineIntersection.html p.intersectLineCircle = function(p1, p2, cpt, r) { let sign = function(x) { return x < 0.0 ? -1 : 1; }; let x1 = p1.copy().sub(cpt); let x2 = p2.copy().sub(cpt); let dv = x2.copy().sub(x1) let dr = dv.mag(); let D = x1.x*x2.y - x2.x*x1.y; // evaluate if there is an intersection let di = r*r*dr*dr - D*D; if (di < 0.0) return []; let t = p.sqrt(di); ip = []; ip.push( new p5.Vector(D*dv.y + sign(dv.y)*dv.x * t, -D*dv.x + p.abs(dv.y) * t).div(dr*dr).add(cpt) ); if (di > 0.0) { ip.push( new p5.Vector(D*dv.y - sign(dv.y)*dv.x * t, -D*dv.x - p.abs(dv.y) * t).div(dr*dr).add(cpt) ); } return ip; } p.inBetween = function(p1, p2, px) { let v = p2.copy().sub(p1); let d = v.mag(); v = v.normalize(); let vx = px.copy().sub(p1); let dx = v.dot(vx); return dx >= 0 && dx <= d; } p.endlessLine = function(x1, y1, x2, y2) { p1 = new p5.Vector(x1, y1); p2 = new p5.Vector(x2, y2); let dia_len = new p5.Vector(p.windowWidth, p.windowHeight).mag(); let dir_v = p5.Vector.sub(p2, p1).setMag(dia_len); let lp1 = p5.Vector.add(p1, dir_v); let lp2 = p5.Vector.sub(p1, dir_v); p.line(lp1.x, lp1.y, lp2.x, lp2.y); } p.draw = function() { if (points.length == 0) { points = []; move = []; for (let i=0; i < 2; ++i ) { points.push( new p5.Vector(p.random(p.windowWidth-20)+10, p.random(p.windowHeight-20)+10)); move.push( new p5.Vector(p.random(2)-1, p.random(2)-1) ); } points.push( new p5.Vector(p.mouseX, p.mouseY)); } else { for (let i=0; i < 2; ++i ) { points[i] = points[i].add(move[i]); if (points[i].x < 10 || points[i].x > p.windowWidth-10) move[i].x *= -1; if (points[i].y < 10 || points[i].y > p.windowHeight-10) move[i].y *= -1; move[i].x = Math.max(-1, Math.min(1, move[i].x+p.random(0.2)-0.1)) move[i].y = Math.max(-1, Math.min(1, move[i].y+p.random(0.2)-0.1)) } points[2].x = p.mouseX; points[2].y = p.mouseY; } let circle_diameter = p.min(p.windowWidth, p.windowHeight) / 2.0; let isectP = p.intersectLineCircle(...points, circle_diameter/2.0); // draw the scene p.background(192); p.stroke(0, 0, 255); p.fill(128, 128, 255); for (let i=0; i < points.length; ++i ) { p.ellipse(points[i].x, points[i].y, 10, 10); } for (let i=0; i < isectP.length; ++i ) { if (p.inBetween(points[0], points[1], isectP[i])) { p.stroke(255, 0, 0); p.fill(255, 128, 0); } else { p.stroke(255, 128, 0); p.fill(255, 255, 0); } p.ellipse(isectP[i].x, isectP[i].y, 10, 10); } p.stroke(0, 255, 0); p.noFill(); p.endlessLine(points[0].x, points[0].y, points[1].x, points[1].y) p.ellipse(points[2].x, points[2].y, circle_diameter, circle_diameter); } p.windowResized = function() { p.resizeCanvas(p.windowWidth, p.windowHeight); points = []; } p.mouseClicked = function() { points = []; } p.keyPressed = function() { points = [] } }; var circle_line = new p5(sketch); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script> <div id="p5js_canvas"></div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM