在Processing中,一个点在一条直线上的正交投影是什么?

3

我在我的processing sketch中有一个线段和一个圆。我想让圆心q找到线段上最近的点p,并使圆朝着它移动。 我不太确定如何编写这个代码(在processing中),所以任何建议都会很棒!谢谢! 这是我目前的代码:

int xPos1 = 200;
int yPos1 = 200;
int xp1 = 50;
int yp1 = 50;
int xp2 = 350;
int yp2 = 50;

void setup() {
    size(400, 400); 
    strokeWeight(2);
    line(xp1, yp1, xp2, yp2);
    strokeWeight(1);
}

void draw() {
    drawCircle();
}

void drawCircle() {
    fill(50, 120, 120);
    //circle
    ellipse(xPos1, yPos1, 75, 75); 
    //circle center
    ellipse(xPos1, yPos1, 7, 7);  
    fill(255);
    text("Q", xPos1 + 15, yPos1 + 5);
    fill(50, 120, 120);
}
2个回答

4
在一条线上,点的投影如下所示:
从具有形式x = a + t * n的直线和一个点p开始。
向量组成部分表示点p到该线上最近点的距离为:
(a - p) - ((a - p)点乘n)n
所以我们得到:p + (a - p) - ((a - p)点乘n)n
简化后我们得到: a - ((a - p)点乘n)n
请注意,((a - p)点乘n) n是表示沿着自最近点到起点(即从最近点到p再返回a)的位置的向量组成部分。
让我们使用PVector使生活变得更加容易。
PVector p = new PVector(200, 200);
PVector a = new PVector(50, 50);
PVector b = new PVector(350, 50);
PVector n = new PVector(350, 50); // |p2 - p1|

void setup() {
    size(400, 400); 
    strokeWeight(2);
    strokeWeight(1);

    // initialize our normalized (unit length) line direction
    n.sub(a);
    n.normalize();
}

void draw() {
    drawCircle();
}

PVector getNearestPointOnLine(PVector p, PVector a, PVector n){
    // the notation turns the computation inside out,
    // but this is equivalent to the above equation
    PVector q = PVector.mult(n, -PVector.sub(a, p).dot(n));
    q.add(a);
    return q;
}

void drawCircle() {
    // lets draw everything here where we can see it
    background(255, 255, 255);
    line(a.x, a.y, b.x, b.y);

    fill(50, 120, 120);
    //circle

    // NOTE: this may require hooking up a mouse move event handler
    p.x = mouseX;
    p.y = mouseY;
    PVector q = getNearestPointOnLine(p, a, n);

    ellipse(q.x, q.y, 75, 75); 
    //circle center
    ellipse(q.x, q.y, 7, 7);  
    fill(0); // make text visible on white background
    text("Q", q.x + 15, q.y + 5);
    //fill(50, 120, 120);
}

参考资料:https://zh.wikipedia.org/wiki/点到直线距离#向量形式


这是关于计算点到直线距离的向量形式的介绍。

请注意,点q仍将出现在线段的任一端之外,即此处没有应用“边界”检查。 - Nolo
谢谢!这非常有帮助。 - B. Boe
我也在寻找的是圆形向线段上最近的点移动的情况。就像我们看到圆形移动一样。对于如何实现这一点,你有什么想法吗?非常期待你的回答! - B. Boe
你可以使用相同的向量公式,其中t是从0到1的值,n是从球到最近点的方向上的归一化向量(即使用我们已经有的变量计算norm(q - p))。维基百科文章通过公式描述了每个向量分量。例如,当t为0时,上述结果将使球位于点p处,当t为1时,球将位于点q处。 - Nolo
如果你需要帮助解决如何在这种情况下给球添加动画效果的问题,只需提出另一个问题。如果你没有得到快速回复,请在这里贴上链接,我下班后可以帮你查看。 - Nolo
我有一个正在进行的另一个草图,它是关于如何在Processing中实现球体动画的新问题的一部分- http://stackoverflow.com/questions/36252964/how-to-move-a-circle-across-a-line-in-processing - B. Boe

0
如果你需要在Javafx中进行实现

vv

AB是一条直线。 P是离直线很近的一个点。 M是离P最近的直线上的点。
  public static Point findPointMOnLineClosestToGivenPointP(Point vector_A, Point vector_B, Point vector_P) {
    Point vector_AB = vector_B.subtract(vector_A);
    Point vector_AP = vector_P.subtract(vector_A);
    double distance_AM = vector_AB.dotProduct(vector_AP) / vector_AB.magnitude();
    Point vector_AM = vector_AB.normalize().multiply(distance_AM);
    Point vector_M = vector_A.add(vector_AM);
    return vector_M;
  }

Point类与javafx.geometry.Point2D类完全相同,只是我将其重命名为Point...


(以下内容不重要)
测试案例和比较
(这个产生的结果与其他答案中的getNearestPointOnLine()相同,类似的数学公式。)
package com.redfrog.trafficsm;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Random;

import org.junit.jupiter.api.Test;

import com.redfrog.trafficsm.model.Point;
import com.redfrog.trafficsm.util.MathUtil;

import processing.core.PVector;

class SimpleTest {

  Random random = new Random(111);

  @Test
  public void test_getNearestPointOnLine() {
    float bound = 100;

    for (int i = 0; i < 100; i++) {
      float f_x;
      float f_y;
      f_x = random.nextFloat(-bound, bound);
      f_y = random.nextFloat(-bound, bound);
      Point point_A = new Point(f_x, f_y);
      PVector pvector_A = new PVector(f_x, f_y);

      f_x = random.nextFloat(-bound, bound);
      f_y = random.nextFloat(-bound, bound);
      Point point_B = new Point(f_x, f_y);
      PVector pvector_B = new PVector(f_x, f_y);
      PVector pvector_N = pvector_B.sub(pvector_A).normalize();

      f_x = random.nextFloat(-bound, bound);
      f_y = random.nextFloat(-bound, bound);
      Point point_P = new Point(f_x, f_y);
      PVector pvector_P = new PVector(f_x, f_y);

      Point point_M = MathUtil.findPointMOnLineClosestToGivenPointP(point_A, point_B, point_P);
      PVector pvector_M = MathUtil.getNearestPointOnLine(pvector_P, pvector_A, pvector_N);

      System.out.println();
      System.out.println(point_M);
      System.out.println(pvector_M);

      int scale = 2;
      System.out.println(MathUtil.round(point_M.getX(), scale));
      System.out.println(MathUtil.round(pvector_M.x, scale));
      System.out.println(MathUtil.round(point_M.getY(), scale));
      System.out.println(MathUtil.round(pvector_M.y, scale));
      assertEquals(MathUtil.round(point_M.getX(), scale), MathUtil.round(pvector_M.x, scale));
      assertEquals(MathUtil.round(point_M.getY(), scale), MathUtil.round(pvector_M.y, scale));
    }

  }

}

package com.redfrog.trafficsm.util;

import java.math.BigDecimal;
import java.math.RoundingMode;

import com.redfrog.trafficsm.model.Point;

import processing.core.PVector;

public class MathUtil {

  public static double round(double value, int scale) {
    return round(value, scale, RoundingMode.HALF_DOWN); // 
  }

  public static double round(double value, int scale, RoundingMode roundingMode) {
    return new BigDecimal(value).setScale(scale, roundingMode).doubleValue(); // 
  }

  // ############

  public static Point findPointMOnLineClosestToGivenPointP(Point vector_A, Point vector_B, Point vector_P) {
    Point vector_AB = vector_B.subtract(vector_A);
    Point vector_AP = vector_P.subtract(vector_A);
    double distance_AM = vector_AB.dotProduct(vector_AP) / vector_AB.magnitude();
    Point vector_AM = vector_AB.normalize().multiply(distance_AM);
    Point vector_M = vector_A.add(vector_AM);
    return vector_M;
  }

  // https://dev59.com/Y-Lxs4cB2Jgan1znp4vr
  public static PVector getNearestPointOnLine(PVector p, PVector a, PVector n) {
    // the notation turns the computation inside out,
    // but this is equivalent to the above equation
    PVector q = PVector.mult(n, -PVector.sub(a, p).dot(n));
    q.add(a);
    return q;
  }
}

JavaFX中的可视化

package com.redfrog.note;

import java.util.Random;

import com.google.common.util.concurrent.AtomicDouble;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Bounds;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import processing.core.PVector;

public class TestAppJavafxBoot extends Application {

  @Override
  public void start(Stage primaryStage) {
    AnchorPane pane_JfxRoot = new AnchorPane();

    AnchorPane panel_SemanticRoot = new AnchorPane();
    pane_JfxRoot.getChildren().add(panel_SemanticRoot);

    final double opacity = 0.9;

    panel_SemanticRoot.setLayoutX(350);
    panel_SemanticRoot.setLayoutY(350);

    Random random = new Random(111);

    float bound = 100;

    float f_x;
    float f_y;

    f_x = random.nextFloat(-bound, bound);
    f_y = random.nextFloat(-bound, bound);
    Point2D point_A = new Point2D(f_x, f_y);
    PVector pvector_A = new PVector(f_x, f_y);

    final Circle circle = new Circle();
    panel_SemanticRoot.getChildren().add(circle);
    circle.setRadius(3);
    circle.setFill(Color.rgb(255, 0, 0, opacity));
    circle.setCenterX(f_x);
    circle.setCenterY(f_y);

    f_x = random.nextFloat(-bound, bound);
    f_y = random.nextFloat(-bound, bound);
    Point2D point_B = new Point2D(f_x, f_y);
    PVector pvector_B = new PVector(f_x, f_y);
    PVector pvector_N = pvector_B.sub(pvector_A).normalize();

    final Circle circle_02 = new Circle();
    panel_SemanticRoot.getChildren().add(circle_02);
    circle_02.setRadius(3);
    circle_02.setFill(Color.rgb(0, 255, 0, opacity));
    circle_02.setCenterX(f_x);
    circle_02.setCenterY(f_y);

    f_x = random.nextFloat(-bound, bound);
    f_y = random.nextFloat(-bound, bound);
    Point2D point_P = new Point2D(f_x, f_y);
    PVector pvector_P = new PVector(f_x, f_y);

    final Circle circle_03 = new Circle();
    panel_SemanticRoot.getChildren().add(circle_03);
    circle_03.setRadius(3);
    circle_03.setFill(Color.rgb(0, 0, 255, opacity));
    circle_03.setCenterX(f_x);
    circle_03.setCenterY(f_y);

    Point2D point_M = MathUtil.findPointMOnLineClosestToGivenPointP(point_A, point_B, point_P);
    PVector pvector_M = MathUtil.getNearestPointOnLine(pvector_P, pvector_A, pvector_N);

    System.out.println();
    System.out.println(point_M);

    final Circle circle_04 = new Circle();
    panel_SemanticRoot.getChildren().add(circle_04);
    circle_04.setRadius(3);
    circle_04.setFill(Color.rgb(0, 255, 255, opacity));
    circle_04.setCenterX(point_M.getX());
    circle_04.setCenterY(point_M.getY());

    final Circle circle_05 = new Circle();
    panel_SemanticRoot.getChildren().add(circle_05);
    circle_05.setRadius(3);
    circle_05.setFill(Color.rgb(255, 255, 0, opacity));
    circle_05.setCenterX(pvector_M.x);
    circle_05.setCenterY(pvector_M.y);


    Scene scene = new Scene(pane_JfxRoot, 950, 750);
    primaryStage.setTitle("DDD");
    primaryStage.setScene(scene);
    primaryStage.show();

  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接